将Nullable值绑定到WPF ComboBox的问题

时间:2009-03-18 19:10:47

标签: wpf combobox data-binding

我将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设置为一个类的实例,该类具有MyEnum类型的名为TheNullableProperty(对于此示例)的属性。

Combo的SelectedValue的绑定在我的XAML文件中完成。

<ComboBox 
  Name="theCombo" 
  SelectedValue="{Binding Path=TheNullableProperty,
                          UpdateSourceTrigger=PropertyChanged}"/>

问题:

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

但是当bound属性的值最初为null时,组合框为空。

当首次显示组合框时,看起来数据绑定的每个方面都与空值的表示不同。

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

我结束了什么

  • 通过转换器将隐藏的文本块数据绑定添加到底层可为空的枚举值,该转换器从可空的枚举转换为字符串(enum.ToString或“null”)。
  • 使用'ComboItems'加载组合框,每个组合框都有一个字符串Label(显示在组合中)和一个字符串值等于枚举值作为字符串(和空值的“null”)。
  • 将组合框数据绑定到文本块。

    /// <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 个答案:

答案 0 :(得分:5)

您无法在WPF(至少3.5 SP1)中按设计绑定到空值。这意味着,当Source获取Null作为值时,您的Binding将自动被破坏,即使您为Source指定了有效值也无法工作。您需要通过Value Converter为您的绑定提供一些“心脏跳动”机制。因此,Converter将null值转换为Targets的某些“Undefined”(非null),并且能够将“Undefined”转换回null ...

答案 1 :(得分:2)

null 作为ComboBoxListBox的有效值似乎存在许多问题,因为类似的问题已被提出here,{ {3}}和here

对于其中任何一个都没有一个极好的,食人魔的回答。

我自己的建议是将Maybe添加为MyEnum的成员。我知道这只是一个例子但如果MyEnum的所有内容都可以为空,那么MyEnum可能应该有一个Undefined成员(或者类似的东西),这对于enums来说很常见

答案 2 :(得分:1)

我在网上找到了这个解决方案,我觉得这个解决方案非常好。我并不完全理解它的实现 - 它是一些非常严肃的.NET功夫 - 但从我作为用户的角度来看它很棒。试一试:

http://philondotnet.wordpress.com/2009/09/18/how-to-select-null-none-in-a-combobox-listbox-listview/

答案 3 :(得分:1)

DependencyProperty.UnsetValue Field

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();
    }
  }
}

答案 4 :(得分:0)

这是解决此问题的一个非常简单的解决方案:

不要在ItemsSource中使用值为null的项目,而是使用DbNull.Value作为项目或项目的value属性。

我在这里详细描述了这种方法:https://stackoverflow.com/a/44170898/6713814