ฉันชอบวัตถุทั้งหมดที่ฉันผูกพันที่จะกำหนดไว้ในของฉันViewModelดังนั้นฉันจึงพยายามหลีกเลี่ยงการใช้<ObjectDataProvider>ใน xaml เมื่อเป็นไปได้
โซลูชันของฉันไม่ใช้ข้อมูลที่กำหนดไว้ในมุมมองและไม่ต้องใช้โค้ด เฉพาะ DataBinding, ValueConverter ที่ใช้ซ้ำได้ซึ่งเป็นวิธีการรับชุดคำอธิบายสำหรับประเภท Enum ใด ๆ และคุณสมบัติเดียวใน ViewModel ที่จะเชื่อมโยง
เมื่อฉันต้องการที่จะผูกEnumกับComboBoxข้อความที่ฉันต้องการที่จะแสดงผลไม่ตรงกับค่าของEnumฉันจึงใช้แอตทริบิวต์ที่จะให้มันข้อความที่จริงผมต้องการที่จะเห็นใน[Description()] ComboBoxถ้าฉันมีจำนวนวันในสัปดาห์มันจะออกมาเป็นแบบนี้:
public enum DayOfWeek
{
  // add an optional blank value for default/no selection
  [Description("")]
  NOT_SET = 0,
  [Description("Sunday")]
  SUNDAY,
  [Description("Monday")]
  MONDAY,
  ...
}
ก่อนอื่นฉันสร้างชั้นผู้ช่วยด้วยวิธีการสองสามอย่างเพื่อจัดการกับ enums วิธีหนึ่งได้รับรายละเอียดสำหรับค่าเฉพาะวิธีอื่นได้รับค่าทั้งหมดและคำอธิบายสำหรับประเภท
public static class EnumHelper
{
  public static string Description(this Enum value)
  {
    var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
    if (attributes.Any())
      return (attributes.First() as DescriptionAttribute).Description;
    // If no description is found, the least we can do is replace underscores with spaces
    // You can add your own custom default formatting logic here
    TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
    return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
  }
  public static IEnumerable<ValueDescription> GetAllValuesAndDescriptions(Type t)
  {
    if (!t.IsEnum)
      throw new ArgumentException($"{nameof(t)} must be an enum type");
    return Enum.GetValues(t).Cast<Enum>().Select((e) => new ValueDescription() { Value = e, Description = e.Description() }).ToList();
  }
}
ValueConverterต่อไปเราจะสร้าง การสืบทอดจากMarkupExtensionทำให้ง่ายต่อการใช้ใน XAML ดังนั้นเราไม่จำเป็นต้องประกาศว่าเป็นทรัพยากร
[ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return EnumHelper.GetAllValuesAndDescriptions(value.GetType());
  }
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    return null;
  }
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    return this;
  }
}
ของฉันViewModelต้องการเพียง 1 คุณสมบัติที่ฉันViewสามารถผูกกับทั้งSelectedValueและItemsSourceคอมโบได้:
private DayOfWeek dayOfWeek;
public DayOfWeek SelectedDay
{
  get { return dayOfWeek; }
  set
  {
    if (dayOfWeek != value)
    {
      dayOfWeek = value;
      OnPropertyChanged(nameof(SelectedDay));
    }
  }
}
และในที่สุดก็ผูกComboBoxมุมมอง (ใช้ValueConverterในการItemsSourceผูก) ...
<ComboBox ItemsSource="{Binding Path=SelectedDay, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
          SelectedValuePath="Value"
          DisplayMemberPath="Description"
          SelectedValue="{Binding Path=SelectedDay}" />
ในการใช้งานโซลูชันนี้คุณจะต้องคัดลอกEnumHelperชั้นเรียนและชั้นเรียนของฉันEnumToCollectionConverterเท่านั้น พวกเขาจะทำงานกับenums ใด ๆ นอกจากนี้ผมไม่ได้รวมไว้ที่นี่ แต่ValueDescriptionชั้นเป็นเพียงระดับที่เรียบง่ายด้วย 2 คุณสมบัติของวัตถุประชาชนคนหนึ่งที่เรียกว่าหนึ่งเรียกว่าValue Descriptionคุณสามารถสร้างด้วยตัวคุณเองหรือคุณสามารถเปลี่ยนรหัสเพื่อใช้Tuple<object, object>หรือKeyValuePair<object, object>