mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

Enumの値をコンボボックスに表示する(Display属性)

Display属性を使ってEnumの値をコンボボックスのアイテムに表示するものを作った。
Description属性を使う場合は別の記事にまとめる。

コンボボックスに表示するEnumをつくる

参照にSystem.ComponentModel.DataAnnotationsを追加すると,Display属性が使えるようになります。
usingを忘れずに。

using System.ComponentModel.DataAnnotations;

各要素にDisplay属性を付けて行きます。
表示したい文字列をDisplay属性のNameプロパティに書きます。

        public enum DisplayCountry
        {
            [Display(Name = "にっぽん")]
            Japane,
            [Display(Name = "あめりか")]
            America,
            [Display(Name = "まれーしあ")]
            Malaysia
        }

Nameプロパティを返すコンバータを作成

ComboBoxConverterを作成して,Display属性のNameプロパティ値を受け取る処理を作ります。
ざっくり説明すると,Enumを引数で受け取ったあと,Nameプロパティを取得しています。

    public class ComboBoxDisplayConverter : IValueConverter
    {
        private string GetEnumName(Enum enumObject)
        {
            if (enumObject == null) return "";
            FieldInfo fieldInfo = enumObject.GetType().GetField(enumObject.ToString());

            object[] attributeArray = fieldInfo.GetCustomAttributes(false);

            if (attributeArray.Length == 0)
            {
                return enumObject.ToString();
            }
            else
            {
                DisplayAttribute attribute = attributeArray[0] as DisplayAttribute;
                if (attribute == null) return string.Empty;
                return attribute.Name;
            }
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Enum myEnum = (Enum)value;
            string description = GetEnumName(myEnum);
            return description;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return string.Empty;
        }
    }

XAMLコンバーターを登録する

先ほど作ったコンバーターをResourceに追加して,使えるようにします。

    <Window.Resources>
        <ResourceDictionary>
            <local:ComboBoxDisplayConverter x:Key="ComboDisplayConverter"/>
        </ResourceDictionary>
    </Window.Resources>

ObjectDataProviderを使ってXAMLからEnumを呼び出せるようにする

コンボボックスのItemsSourceプロパティに準備したDisplayCountry列挙型を割り当てるための準備です。
別クラスの値にアクセスするときは,"クラス名+変数名"のように書くとアクセスできる。

    <Window.Resources>
        <ResourceDictionary>
            <local:ComboBoxDisplayConverter x:Key="ComboDisplayConverter"/>

            <ObjectDataProvider x:Key="DisplayCountryOptions" MethodName="GetValues" ObjectType="{x:Type local:MainWindowViewModel+DisplayCountry}">
                <ObjectDataProvider.MethodParameters>
                    <x:Type TypeName="local:MainWindowViewModel+DisplayCountry"/>
                </ObjectDataProvider.MethodParameters>
            </ObjectDataProvider>
        </ResourceDictionary>
    </Window.Resources>

準備が整いました。ComboBoxから呼び出して見ましょう。

ObjectDataProviderで登録したKeyを使って,ItemsSoueceにDisplayCountry列挙型を与えます。
(SelectedItemはおまけです。後で説明します。)
ComboBox.ItemTemplateでDisplayCountry列挙型の値をDisplay属性のNameプロパティに変換して表示する処理を記述します。

        <StackPanel Margin="10">
            <TextBlock Text="Displayを使う場合:"/>
            <ComboBox
                ItemsSource="{Binding Source={StaticResource ResourceKey=DisplayCountryOptions}}"
                SelectedItem="{Binding Path=SelectedDisplayCountry}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Converter={StaticResource ComboDisplayConverter}}" />
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>

SelectedItemは,以下のようなプロパティえを用意してバインドさせてあげると取得できます。

        private DisplayCountry _selectedDisplayCountry;
        public DisplayCountry SelectedDisplayCountry
        {
            get { return _selectedDisplayCountry; }
            set { SetProperty(ref _selectedDisplayCountry, value); }
        }

完成

見た目はこんな感じ
f:id:mogmo811:20181031172037p:plain