20210612のC#に関する記事は5件です。

[WPF/xaml] ListViewのGrid表示を使う

やりたいこと ListViewに、自分で作ったデータ用クラスのメンバを表示させたい。下記のようなイメージ。 やりかた <ListView>と<GridView>を使う。 MainWindow.xaml <Window x:Class="WpfApp48.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp48" mc:Ignorable="d" Title="MainWindow" Height="300" Width="200"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="10*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions> <ListView ItemsSource="{Binding DataList}"> <ListView.View> <GridView> <GridViewColumn Header="機体" DisplayMemberBinding="{Binding MachineName}" Width="80" /> <GridViewColumn Header="パイロット" DisplayMemberBinding="{Binding PilotName}" Width="80" /> </GridView> </ListView.View> </ListView> <Button Grid.Row="1" Content="ボタン" Click="Button_Click"/> </Grid> </Window> MainWindow.xaml.cs using System; using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows; namespace WpfApp48 { public partial class MainWindow : Window, INotifyPropertyChanged { #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName)=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); #endregion // ガンダム情報を格納 public ObservableCollection<MyData> DataList { get; set; } = new ObservableCollection<MyData>(); public MainWindow() { InitializeComponent(); this.DataContext = this; } // ボタンをおしたらデータの中身を追加 private void Button_Click(object sender, RoutedEventArgs e) { DataList.Add(new MyData() { MachineName = "ガンダム", PilotName = "アムロ" }); DataList.Add(new MyData() { MachineName = "シャアザク", PilotName = "シャア" }); DataList.Add(new MyData() { MachineName = "グフ", PilotName = "誰やったっけ?" }); DataList.Add(new MyData() { MachineName = "Zガンダム", PilotName = "カミーユ" }); DataList.Add(new MyData() { MachineName = "ジ・オ", PilotName = "シロッコ" }); DataList.Add(new MyData() { MachineName = "百式", PilotName = "シャア" }); DataList.Add(new MyData() { MachineName = "ZZガンダム", PilotName = "ジュドー" }); } } /// <summary> /// ガンダム情報クラス /// </summary> public class MyData { public string MachineName { get; set; } public string PilotName { get; set; } } } <GridViewColumn>のHeaderに、列のタイトルを書き、DisplayMemberBindingに、列に表示したいデータクラスのメンバの名前を書く。 参考 ListView(MsDocs) ListViewのカスタムの仕方が書いてある ListViewのグループ ツリービューでもいいかも?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ExpandoObjectクラスを使ってみた

ExpandoObjectクラスを使ってみた 業務の中で使用する場面があったので、備忘録として残しておきます。 どんなクラス? 「System.Dynamic」名前空間のクラス。事前に定義していない型のオブジェクトに対して、動的にプロパティを設定することができる。 実際に使ってみた ExpandoObjectのインスタンスを生成し,動的にプロパティを設定 using System; using System.Dynamic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { //ExpandoObjectクラスのインスタンスを生成 dynamic obj = new ExpandoObject(); //プロパティを設定 obj.Height = 100; obj.Width = 50; //各プロパティを出力 Console.WriteLine("Height: {0}", obj.Height); Console.WriteLine("Width: {0}", obj.Width); } } } 出力結果 Height: 100 Width: 50 Apple Strawberry Grapes 30 40 JsonにSeriaizeしてみた ExpandoObjectで生成したオブジェクトをJsonにSerializeする。 using System; using System.Collections.Generic; using System.Dynamic; namespace ConsoleApp1 { class Program { static void Main(string[] args) { //ExpandoObjectクラスのインスタンスを生成 dynamic obj = new ExpandoObject(); //List var list = new List<string>(); list.Add("Apple"); list.Add("Strawberry"); list.Add("Grapes"); //Dictionary var dict = new Dictionary<string, int>(); dict.Add("Apple", 400); dict.Add("Strawberry", 600); dict.Add("Grapes", 500); //プロパティを設定 obj.Height = 100; obj.Width = 50; obj.fruits = list; obj.people = dict; //各プロパティを出力 Console.WriteLine("Height: {0}", obj.Height); Console.WriteLine("Width: {0}", obj.Width); Console.WriteLine(obj.fruits[0]); Console.WriteLine(obj.fruits[1]); Console.WriteLine(obj.fruits[2]); Console.WriteLine(obj.people["taro"]); Console.WriteLine(obj.people["jiro"]); } } } 出力結果 {"fruits":{"Apple":400,"Strawberry":600,"Grapes":500}} どんなJsonでもDeserializeしてみたい 構造がわからないJsonをExpandoObjectを使ってDeserializeする。 sample.json { "Name": "Taro", "Age": 30, "Country": "Tokyo", "Skill": [ "Football", "Guitar" ] } using Newtonsoft.Json; using System; using System.Dynamic; using System.IO; namespace ConsoleApp1 { class Program { static void Main(string[] args) { //Jsonファイル読み込み var sr = new StreamReader(@"C:\work\sample.json"); var json = sr.ReadToEnd(); //ExpandoObjectクラスのインスタンスを生成 dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json); //プロパティ出力 Console.WriteLine(obj.Name); Console.WriteLine(obj.Age); Console.WriteLine(obj.Country); Console.WriteLine(string.Join(",", obj.Skill)); } } } 出力結果 Taro 30 Tokyo Football,Guitar さいごに 今後の業務でもお世話になりそうです。忘れたら見直そう~
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

snippet: C#

コンパイル方法 キー入力 main.cs using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { // Altキー押しながらf SendKeys.SendWait("(%f)"); System.Threading.Thread.Sleep(100); // aキー SendKeys.SendWait("a"); System.Threading.Thread.Sleep(100); } } } 文字 コンソール出力(途中改行付き) main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { // 改行は \n string str = "あいうえおabcdeかきくけこ\nさしすせそタチツテト"; p(str); } } } 改行付き文字を変数に入れる main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { string str = @"いろは にほへと "; p(str); } } } 文字を繰り返す 10個あを表示 main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { string text = ""; for (int i=0; i<10; i++) { text += "あ"; } p(text); } } } main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { string text = new String('あ', 10); p(text); } } } 文字列の置換(正規表現) main.cs using System; using System.Text.RegularExpressions; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { string inputText = @"<div>aaa</div><div>bbb</div>"; // HTMLタグを除去する例 string pattern = @"<.*?>"; // 空白だけの行を除去。1行ごとに処理するので、RegexOptions.Multilineを指定 string ResultText = Regex.Replace(inputText, pattern, "", RegexOptions.Multiline); // aaabbb p(ResultText); } } } コマンドラインから入力した文字を扱う main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { p(@"なにか入力してください: "); string InputText = Console.ReadLine(); p(InputText); } } } メモ: Console.Inを使う場合は、Control-Dで入力を終える。 音を出す(Beep) main.cs using System; using System.Runtime.InteropServices; class BeepProgram { [DllImport("kernel32.dll")] private extern static bool Beep(uint dwFreq, uint dwDuration); private static void Main() { Beep(262, 500); // ド Beep(294, 500); // レ Beep(330, 500); // ミ Beep(349, 500); // ファ Beep(392, 500); // ソ Beep(440, 500); // ラ Beep(494, 500); // シ Beep(523, 500); // ド } } コマンドライン コマンドライン引数 main.exe 1 2 3 main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { p(Environment.CommandLine); // forループで分割 string[] str = Environment.GetCommandLineArgs(); foreach(string s in str) { p(s); } p(str[1]); p(str[2]); } } } sleep main.cs using System; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { p("sleep start"); // 3秒スリープ System.Threading.Thread.Sleep(3000); p("sleep end"); } } } テキストファイルの読み込み 改行区切り main.cs using System; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace ConsoleApp1 { class Program { static void p(string str) { Console.WriteLine(str); } static void Main(string[] args) { // 読み込み string source = File.ReadAllText("main.cs", Encoding.GetEncoding("shift_jis")); // 行末のスペースを無視しつつ、改行区切り string pattern = @"\s*\r\n"; string[] lines = Regex.Split(source, pattern); // 正規表現で分割 foreach(var line in lines) { p(line); } } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

System.CommandLine コマンドラインパーサーを利用する

C# を使っているときに、コマンドラインツールを作るときに便利なコマンドラインパーサーないかな?と思って調査したところ、最もオフィシャルに近い System.CommandLine を試してみることにしました。自分がしたいことを中心に調べたことをまとめてみたいと思います。 System.CommandLine を使用してコマンド ラインを解析する GitHub Project 基本的な使い方 RootCommand というクラスをインスタンス化して、そこに、AddArgument, AddOption で引数やオプションを渡します。最後に Invoke または、InvokeAsync を実行してあげるとよいです。Main メソッドの中で呼ばれるようにしてみてください。 Program.cs static async Task<int> Main(string[] args) { var rootCommand = new RootCommand { Description = "Update the configuration file of the LinuxPoolConfig" }; rootCommand.AddArgument(new Argument<int>("stage", "Stage Number for update e.g. 1")); Option sourceOption = new Option<string>( new string[] {"--source", "-s"}, "Source Version for update. e.g. 3.0.17892 By default, this tool update update version that matches the major version of target version." ); rootCommand.AddOption(sourceOption); rootCommand.AddArgument(new Argument<string>("target", "Target Version for update. e.g. 3.0.17893")); Option configFileOption = new Option<FileInfo>( aliases: new string[] {"--config-file", "-c"}, description: "Config file to update"); rootCommand.AddOption(configFileOption); rootCommand.Handler = CommandHandler.Create<int, string, string, FileInfo, IConsole>(new UpdateAction().Execute); return await rootCommand.InvokeAsync(args); } すると、Helpを自動で作成してれます。MyConfigCmd はプロジェクト名です。 Help MyConfigCmd Update the configuration file of the MyConfig Usage: MyConfigCmd [options] <stage> <target> Arguments: <stage> Stage Number for update e.g. 1 <target> Target Version for update. e.g. 3.0.17893 Options: -s, --source <source> Source Version for update. e.g. 3.0.17892 By default, this tool update update version that matches the major version of target version. -c, --config-file <config-file> Config file to update --version Show version information -?, -h, --help Show help and usage information 実行の例は次のような感じです。 $ MyConfigCmd.exe 0 3.0.15829 --source 3.0.15828 --config-file .\Hello\config.json 必須・オプションパラメータの表現 必須項目 必須項目は、Argument で表現します、必須項目の型、名前、概要を定義できます。概要は、help でも使われます。 Argument rootCommand.AddArgument(new Argument<int>("stage", "Stage Number for update e.g. 1")); オプション オプションの項目は、次のように書くことで、 追加することができます。alias を定義することで、オプションの書き方や、省略形の書き方も設定できます。また、getDefaultValue() に対して関数を渡すことでデフォルト値を設定することができます。 Option Option configFileOption = new Option<FileInfo>( aliases: new string[] {"--config-file", "-c"}, description: "Config file to update", getDefaultValue: () => new FileInfo(Path.Combine(".", "config"))); rootCommand.AddOption(configFileOption); Sub Command Sub Command は、今回必要なかったので試していませんが Add SubCommand を見ると、Command というクラスをインスタンス化して、RootCommand に足してあげるとよいだけのようです。 ハンドラの実行 さて、このコマンドアプリが実行されたら、何らかのアクションを実行したいと思います。このように設定します。 Handler rootCommand.Handler = CommandHandler.Create<int, string, string, FileInfo, IConsole>(new UpdateAction().Execute); ここで、ポイントは、ここで渡しているハンドラの名前です。定義したArgument や、Option で定義した名前と同じ引数名にする必要があります。Argument は名前が明確なので、わかりやすいですが、Option は、aliasしかないし、--config-file とかの場合どうなるの?と思うと思いますがこの場合は、configFile というキャメルケースになるようです。私はここが最初わからなくて、パラメータが渡ってこないという問題に遭遇しました。 UpdateAction.Execute public int Execute(int stage, string source, string target, FileInfo configFile, IConsole console) { : 終了ステータス コマンドラインアプリを作っていると、終了ステータスを定義したいと思います。実は、先ほどのハンドラは戻り値無しでもかけるのですが、先ほど紹介した通り戻り値をint として定義しています。そうすると、この部分が終了ステータスになるので、return 1; とか返すと、エラーの終了ステータスになりますので便利です。 ユニットテストで便利な機能 先ほどのハンドラの部分で、IConsole という謎のパラメータがあります。これをつけてあげると、Console のオブジェクトを引き取ることができます。コンソールへの出力は次のように標準出力にも、エラー出力にも書くことができます。 Console if (configFile == null || !File.Exists(configFile?.FullName)) { console.Error.WriteLine($"config file : {configFile} does not exists."); return 1; } console.Out.WriteLine($"executing.... Stage: {stage}, SourceVersion: {source}, TargetVersion : {target}, ConfigFile : {configFile?.FullName}"); : これが何が良いか?というと、このハンドラのユニットテストを書くと、次のような感じで書くことができます。つまり、コンソールのMockを渡して、エラーの時のメッセージを簡単にテストすることができます。 TestSomething.cs TestConsole console = new TestConsole(); var status = new UpdateAction().Execute(0, "3.0.15828", "3.0.15829", new FileInfo(wrongConfigPath), console); console.StdErr().Flush(); string output = Encoding.UTF8.GetString(console.StdErr().ToArray()); Assert.Contains($"config file : {wrongConfigPath} does not exists.", output); TestConsole.cs public class TestConsole :IConsole { public IStandardStreamWriter Out { get; } = new TestConsoleStandardOutputWriter(); public bool IsOutputRedirected { get; } public IStandardStreamWriter Error { get; } = new TestConsoleStandardErrorWriter(); public bool IsErrorRedirected { get; } public bool IsInputRedirected { get; } public MemoryStream StdOut() { return ((TestConsoleStandardOutputWriter) Out).Message; } public MemoryStream StdErr() { return ((TestConsoleStandardErrorWriter) Error).Message; } } public class TestConsoleStandardOutputWriter : IStandardStreamWriter { public MemoryStream Message { get; } = new MemoryStream(); public void Write(string value) { Message.Write(Encoding.UTF8.GetBytes(value)); } } public class TestConsoleStandardErrorWriter : IStandardStreamWriter { public MemoryStream Message { get; } = new MemoryStream(); public void Write(string value) { Message.Write(Encoding.UTF8.GetBytes(value)); } } おわりに 私のやりたいことは、大体 System.CommandLineで出来る感じなので、今後も使っていこうと思います。ちなみに、まだβなので、はよGAになって欲しいですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MSBuild.exeで実行ファイルを作る

csc.exe での実行ファイル作成に限界を感じたのでMSBuild.exeを使うこととした。 ファイル main.csproj <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Compile Include="*.cs" /> </ItemGroup> <Target Name="Build"> <Csc Sources="@(Compile)" References="@(Reference)" /> </Target> </Project> References=でdll読み込みの指定を渡すことができる。 ToolsVersion="4.0"を書かないと古いC#の記述方法しか使えなかった。 ソースファイル main.cs using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Console.Write("hello"); } } } ビルドスクリプト compile.bat del main.exe C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ^ main.csproj main.exe pause 実行ファイルを作る DLLの追加 main.csproj <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Compile Include="*.cs" /> <Reference Include="QRCodeEncoderDecoderLibrary.dll"/> </ItemGroup> <Target Name="Build"> <Csc Sources="@(Compile)" References="@(Reference)" /> </Target> </Project>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む