C#
WPF
Xaml

列挙型をComboBoxにバインドする

やりたいこと

ViewModelのプロパティを使わずに、列挙型をComboBoxのItemsSourceにバインドする。ただし、表示名はメンバー名ではなく別途指定できるようにする。

実装

列挙型を直接バインドできないため、ソースを提供するクラスを作成する。

ソースを提供するクラス
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows.Markup;

namespace Sample {
    public class EnumSourceProvider<T> : MarkupExtension {
        private static string DisplayName(T value) {
            var fileInfo = value.GetType().GetField(value.ToString());
            var descriptionAttribute = (DescriptionAttribute)fileInfo
                .GetCustomAttributes(typeof(DescriptionAttribute), false)
                .FirstOrDefault();
            return descriptionAttribute.Description;
        }

        public IEnumerable Source { get; } 
            = typeof(T).GetEnumValues()
                .Cast<T>()
                .Select(value => new { Code = value, Name = DisplayName(value) });

        public override object ProvideValue(IServiceProvider serviceProvider) => this;
    }
}

使い方

列挙型
namespace Sample {
    //表示させたい文字列をDescription属性に指定する
    public enum EnumSample {
        [Description("項目1")]
        A,
        [Description("項目2")]
        B,
        [Description("項目3")]
        C,
        [Description("項目4")]
        D
    }

    public class EnumSampleSourceProvider : EnumSourceProvider<EnumSample> { }
}
XAML
<Window x:Class="Sample.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Sample"
        Title="MainView" Height="300" Width="300">
    <Grid>
        <ComboBox ItemsSource="{Binding Source, Source={local:EnumSampleSourceProvider}}"
                  DisplayMemberPath="Name" 
                  SelectedValuePath="Code" />
    </Grid>
</Window>