将可空值绑定到WPF ComboBox时出现问题

6

我正在将一个WPF ComboBox绑定到一个可空的MyEnum?类型属性(其中MyEnum是一个枚举类型)

我正在使用编程方式填充ComboBox项目,如下所示:

// The enum type being bound to 
enum MyEnum { Yes, No }

// Helper class for representing combobox listitems
// (a combination of display string and value)
class ComboItem {
  public string Display {get;set}
  public MyEnum? Value {get;set}
}

private void LoadComboBoxItems()
{
  // Make a list of items to load into the combo
  var items = new List<ComboItem> {
    new ComboItem {Value = null, Display = "Maybe"},
    new ComboItem {Value = MyEnum.Yes, Display = "Yes"},
    new ComboItem {Value = MyEnum.No, Display = "No"},};

  // Bind the combo's items to this list.
  theCombo.ItemsSource = items;
  theCombo.DisplayMemberPath = "Display";
  theCombo.SelectedValuePath = "Value";
}

在代码后台,我将DataContext设置为一个具有名为TheNullableProperty(例如此示例)类型为MyEnum?的属性的类的实例。
在我的XAML文件中完成了Combo的SelectedValue绑定。
<ComboBox 
  Name="theCombo" 
  SelectedValue="{Binding Path=TheNullableProperty,
                          UpdateSourceTrigger=PropertyChanged}"/>

问题:

当绑定属性的值最初为非空时,组合框会正确显示该值。

但是,当绑定属性的值最初为空时,组合框为空白。

看起来数据绑定的各个方面都在工作,除了在首次显示组合框时表示空值。

例如:您可以从下拉列表中选择“可能”,并且绑定属性将正确设置为空。只是初始加载失败了。也许我需要手动设置SelectedValue...

我的解决方案

  • Add a hidden textblock databound to the underlying nullable enum value via a Converter that converts from the nullable enum to a string (enum.ToString, or "null").
  • Load up the combo box with 'ComboItems' each having a string Label (displayed in the combo) and a string Value equal to the enum values as strings (and "null" for the null value).
  • Data-bind the combo box to the textblock.

    /// <summary>
    /// Convert from EnumeratedType? to string (null->"null", enum values->ToString)
    /// </summary>
    public class EnumConverter<T> : IValueConverter where T:struct 
    {
      public static string To(T? c)
      {
        if (c == null)
          return "null";
        return c.ToString();
      }
    
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {
        return To((T?)value);
      }
    
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
        var s = (string) value;
        if (s == "null")
          return null;
        return (T?)Enum.Parse(typeof(T), s);
      }
    }
    
    public class MyEnumConverter : EnumConverter<MyEnum>
    {
    }
    
    public class ComboItem
    {
      public string Value { get; set; }
      public string Label { get; set; }
    
      public ComboItem(MyEnum? e, string label)
      {
        Value = MyEnumConverter.To(e);
        Label = label;
      }
    }
    
    static IEnumerable<ComboItem> GetItems()
    {
      yield return new ComboItem(null, "maybe");
      yield return new ComboItem(MyEnum.Yes, "yup");
      yield return new ComboItem(MyEnum.No, "nope");
    }
    
    private void SetupComboBox()
    {
      thecombo.ItemsSource = GetItems().ToList();
    }
    
5个回答

5
在WPF(至少3.5 SP1)中,按设计不能将绑定到空值。这意味着当源接收到Null值时,您的绑定将自动断开,并且即使您为源指定了有效值,它也无法工作。您需要通过值转换器提供一些“心跳”机制来维护绑定。因此,转换器可以将null值转换为某些“未定义”(非空)用于目标,然后能够将您的“未定义”转回为null...

1
我认为在ItemsControls的情况下,null是一个特殊的值。只要提供转换器,就可以将null绑定到例如TextBlock。但是,转换器对于使ItemsControls接受null作为所选项目没有帮助。 - mackenir

2

2

似乎许多问题都与在ComboBoxListBox中使 null 成为有效值有关,因为类似的问题已经在这里这里这里被问到了。

至今还没有一个超级的、能够解决这些问题的答案。

我的建议是将 Maybe 添加为 MyEnum 的成员。我知道这只是一个示例,但如果所有具有 MyEnum 的内容都具有可空性,那么 MyEnum 可能应该有一个Undefined 成员(或类似的内容),这在枚举中非常普遍。


在这种情况下,MyEnum是从XSD生成的,并且绑定到的类型为MyEnum的属性是“可选的”,因此null表示“属性不存在”。这是在C#中表示属性的相当不错的方式,但如果WPF ComboBox无法处理它,我想我必须做些其他的事情。 - mackenir

1

DependencyProperty.UnsetValue字段

using System;

using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace MyConverters
{
  [ValueConversion(typeof(DateTime), typeof(String))]
  public class StringToIntConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      int number;

      return int.TryParse(value.ToString(), out number) ? number : DependencyProperty.UnsetValue;
    }

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

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接