〰️

【WPF, XAML】Enum値をGUI上に表示する方法 (xamlオンリー)

2023/01/29に公開

はじめに

今回はWPFでEnum値をComboBoxに全てありのまま表示する方法を紹介する。これはListBoxでも何でも良い。
表示文字列のローカライズについては主旨が異なるため触れない。
また、記事中に示す例ではINotyfyPropertyChanged周辺の記述は省略している。適宜読み替えること。

背景

軽く調べた限り日本語で紹介されている情報のほとんどは、下記例のようにViewModelないしModelでEnum値を網羅したプロパティを定義し、それをBindingするようなアプローチが取られている。

ViewModelでBinding元データを定義する例
public class SampleViewModel {
    public enum E {
        Enum1,
        Enum2,
        Enum3,
    }
    public IEnumrable<E> Es { get; private set; } = Enum.GetValues<E>();    // これ
}
xaml側の記述
<ComboBox ItemsSource="{Binding Es}"/>

記述量で言えばぶっちゃけこれが一番シンプルだし、これで終わりなら私がこんな記事書く意味もないのだが、個人的に少し気になるのはViewでしか使わないプロパティ(上記例で言うEs)をView以外で定義している点である。Viewで必要なプロパティをViewModelで定義することについてはおかしくないとか、そういう宗教じみたMVVMの話について触れる気はない。
もちろん上記例のEsをViewModelでも使うのであれば全く問題は無い

Enum値を網羅したプロパティをxamlで定義する

いい加減能書きが長くなって申し訳無いので答えを書く。

ViewModelはEnum定義だけ
public class SampleViewModel {
    public Enum E {
        Enum1,
        Enum2,
        Enum3,
    }
}
必要なプロパティはなにがなんでもxamlで作る
<ComboBox>
    <ComboBox.ItemsSource>
        <Binding>
            <Binding.Source>
                <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
                    <ObjectDataProvider.MethodParameters>
                        <x:Type TypeName="local:SampleViewModel+E" />
                    </ObjectDataProvider.MethodParameters>
                </ObjectDataProvider>
            </Binding.Source>
        </Binding>
    </ComboBox.ItemsSource>
</ComboBox>

この異常な階層構造を見てあなたは思ったかもしれない。これ意味ある?
Enum値を使いまわしたければObjectDataProviderをStaticResource化しても良いし、マークアップ拡張にすることも当然可能である。
上記コードは言ってしまえばViewModelに書いていたロジックをxamlで書いただけな訳だが、どちらに価値を感じるかはその人の設計思想によるため最終的には好きにすれば良いと思う。

Discussion