ちおさん雑記帳

何の役にも立たない雑記から、誰かの役に立つ(かも知れない)メモなど・・

WPF DataGridを使ってみる(1)

という訳で、唐突ですが業務で初めてWPFを触ってみたので復習がてら、メモとして記録。


まず新規でWPFアプリケーションを作成します。

f:id:caffe1208:20200312154317g:plain

新規作成直後はこのように空のWindowにGridが配置されただけの状態になっていますので、ここにDataGridを追加します。

    <Grid>
        <DataGrid x:Name="Grid1"
			AutoGenerateColumns="False" HeadersVisibility="Column">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding CharName}" Header="名前"/>
                <DataGridTextColumn Binding="{Binding Job}" Header="職業"/>
                <DataGridTextColumn Binding="{Binding Level}" Header="年齢"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>


こんな感じで、変数名は何でも良いのですが、ここでは Grid1 とします。
列としては、「名前」「職業」「年齢」を表示させるようにしたいと思います。

こうするとXAMLデザイナ上でも

f:id:caffe1208:20200312155159p:plain


このように、列が3つ追加されているのが分かります。

次にDataGridに表示させるデータを入れるための器となるクラスを作成します。

namespace WpfGridSample
{
    public class MyInfo
    {
        public string CharName { get; set; }    // 名前
        public string Job { get; set; }         // 職業
        public int Level { get; set; }          // レベル
    }

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

ここもクラス名は何でも良いですが、MyInfoクラスとしました。
MyInfoクラスのプロパティはDataGridで表示させようとする列のBindingに指定した名前と同じものを定義しておく必要があります。
XAML側に"CharName","Job","Level"にBindする指定としましたので、これらをプロパティに持つクラスを定義すれば良いです。

ではDataGridに情報を表示するコードを作っていきましょう。
DataGridに表示させたい1件分の情報になるMyInfoクラスのオブジェクトを生成するメソッドを、

        private MyInfo CreateCharInfo(string strName, string strJob, int level)
        {
            var myInfo = new MyInfo() {
                CharName = strName,
                Job = strJob,
                Level = level
            };
            return myInfo;
        }


こんな感じで用意し(別に用意しなくても表示は出来ますが・・)、これを画面起動時に呼び出してみましょう。

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var myInfoCollection = new ObservableCollection<MyInfo>();
            myInfoCollection.Add(CreateCharInfo("なまえA", "WhiteMage", 30));
            myInfoCollection.Add(CreateCharInfo("なまえB", "BlackMage", 32));

            Grid1.ItemsSource = myInfoCollection.ToList();
        }


Loadedイベント時にMyInfoクラスオブジェクト生成したものをObservableCollectionにAddして、2人分の情報を追加し、DataGridのItemsSourceにセットします。ItemsSourceにはObservableCollectionそのままだとセット出来ない為、ToList()を行いList化しています。

さて、実行してみると、

f:id:caffe1208:20200312160233p:plain


このようにDataGridに生成した情報が表示されました。

名前、職業はstring型ですが、職業の方をenumに変えてみましょう。

    public enum JobKind
    {
        Knight = 0,
        Warrior,
        BlackMage,
        WhiteMage,
        Scholar
    }


こんな感じでenumを定義して、さきほどのMyInfoクラス内のプロパティ職業の型を変更して、オブジェクトの生成処理も型を変更しましょう。


変更した後のソースは以下のようになります。

    public class MyInfo
    {
        public string CharName { get; set; }    // 名前
        public JobKind Job { get; set; }         // 職業
        public int Level { get; set; }          // 年齢
    }

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var myInfoCollection = new ObservableCollection<MyInfo>();
            myInfoCollection.Add(CreateCharInfo("なまえA", JobKind.WhiteMage, 30));
            myInfoCollection.Add(CreateCharInfo("なまえB", JobKind.BlackMage, 32));

            Grid1.ItemsSource = myInfoCollection.ToList();
        }
        private MyInfo CreateCharInfo(string strName, JobKind jobkind, int level)
        {
            var myInfo = new MyInfo() {
                CharName = strName,
                Job = jobkind,
                Level = level
            };
            return myInfo;
        }
    }


さて、では実行してみましょう。


f:id:caffe1208:20200312160423p:plain


さっきまでの結果と(見た目上では)何ら変わらない表示になりました。

では、WhiteMageの時は「白魔導士」、BlackMageの時は「黒魔導士」と表示させたい場合を考えてみます。

何通りか方法はあるのですが、今回はリソースに各職業に対応する日本語を定義しておき、そこから職業のenumに該当する文字列を取得して表示させる方法で考えてみます。

まず、リソースに以下のような各enum値に対応する日本語文字列を定義してみましょう、


f:id:caffe1208:20200312160624p:plain

こんな感じで(ついでに1ジョブ増やしています)リソースを定義。

DataGridに表示する職業をstringに変更(最初の状態に戻す)ので、MyInfoクラスの定義は

    public class MyInfo
    {
        public string CharName { get; set; }    // 名前
        public string Job { get; set; }         // 職業
        public int Level { get; set; }          // 年齢
    }

上記のようにします。

次に、enum値の職業から該当する(リソースに定義追加した)日本語文字列を取得するメソッドを作成してみます。

        private string GetJobString(JobKind _job)
        {
            return Properties.Resources.ResourceManager.GetString(_job.ToString());
        }


Properties.Resources.ResourceManager.GetString()メソッドは引数で指定の名前に該当する値が返却されます。
上記までのサンプルでは例えば、"Knight"を指定すると"ナイト"が返却さます。
_job.ToString()としていることで、JobKind.Knightのような値を"Knight"のような文字列型にして引数に渡しています。

MyInfoクラスのプロパティ「職業」の型をenumからstringに変更したので、1人分の情報であるMyInfoクラスオブジェクトを生成するメソッドを変更します。

        private MyInfo CreateCharInfo(string strName, JobKind jobkind, int level)
        {
            var myInfo = new MyInfo() {
                CharName = strName,
                Level = level
            };
            myInfo.Job = GetJobString(jobkind);
            return myInfo;
        }

メソッドの引数及び戻り値は変更されていませんが、MyInfoクラスのJobプロパティの型が変わっているため、変換(enum → 日本語文字列)メソッドを呼び出して結果をJobプロパティにセットしています。

MyInfoクラスの初期化を記述する方法では、メソッドを呼び出して戻り値を採用したい場合に対応していない為ビルドエラーとなりますので、Jobのenum値からリソースで定義した文字列を取得するメソッドの戻り値をセットするように変更しています。

さて、ついでにLoadedイベントで生成しているMyInfoクラスの個数を2から4に増やしてみます。

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            var myInfoCollection = new ObservableCollection<MyInfo>();
            myInfoCollection.Add(CreateCharInfo("ちおさん", JobKind.Knight, 38));
            myInfoCollection.Add(CreateCharInfo("でいちゃん", JobKind.Samurai, 30));
            myInfoCollection.Add(CreateCharInfo("かんぺい", JobKind.BlackMage, 51));
            myInfoCollection.Add(CreateCharInfo("ねこきなこ", JobKind.WhiteMage, 17));

            Grid1.ItemsSource = myInfoCollection.ToList();
        }


こんな感じに変更しています。

さぁ実行してみましょう。

f:id:caffe1208:20200312160934p:plain

リソースい定義した日本語文字列で表示されました。

追伸
文中および画像の中で”*魔導士”と記述されていますが、”**魔道士”が表記としては正解になります。
修正は出来ないため、そのままとなりますがご容赦ください。