为什么我不能在ComboBox中select一个空值?

在WPF中,从ComboBox中select(使用鼠标)“null”的值似乎是不可能的。 编辑为了澄清,这是.NET 3.5 SP1。

这里有一些代码来展示我的意思。 首先,C#声明:

public class Foo { public Bar Bar { get; set; } } public class Bar { public string Name { get; set; } } 

接下来,我的Window1 XAML:

 <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <ComboBox x:Name="bars" DisplayMemberPath="Name" Height="21" SelectedItem="{Binding Bar}" /> </StackPanel> </Window> 

最后,我的Window1类:

 public partial class Window1 : Window { public Window1() { InitializeComponent(); bars.ItemsSource = new ObservableCollection<Bar> { null, new Bar { Name = "Hello" }, new Bar { Name = "World" } }; this.DataContext = new Foo(); } } 

跟我? 我有一个ComboBox的项目绑定到一个Bar实例列表,其中一个是null。 我已经将窗口绑定到Foo的实例,并且ComboBox正在显示其Bar属性的值。

当我运行这个应用程序时,combobox以空显示开始,因为默认情况下Foo.Bar为空。 没关系。 如果我使用鼠标放下combobox并select“Hello”项目,那也可以。 但是,如果我尝试重新select列表顶部的空项目,则combobox将closures并返回到之前的值“Hello”!

使用箭头键select空值,按预期方式工作,并以编程方式进行设置。 这只是用鼠标select不起作用。

我知道一个简单的解决方法是有一个Bar的实例代表null,并通过IValueConverter运行它,但有人可以解释为什么用鼠标selectnull在WPF的ComboBox中不起作用?

键盘根本没有select空的“项目”,而是先前的项目被取消select,并且没有后续的项目(能够)被select。 这就是为什么在用键盘“select”空项之后,除了通过鼠标之外无法重新select之前select的项(“你好”)!

总之,你既不能在ComboBox中select也不能取消select一个空的项目。 当你认为你这样做的时候,你宁愿取消select或select以前的或新的项目。

通过为ComboBox中的项目添加背景,最好也可以看到这一点。 当您select“Hello”时,您会注意到ComboBox中的彩色背景,但是当您通过键盘取消select时,背景颜色会消失。 我们知道这不是空项目,因为当我们通过鼠标放下列表时,空项目实际上具有背景颜色!

下面的XAML(从原始问题中修改)将在项目后面放置一个LightBlue背景,以便您可以看到此行为。

 <Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <StackPanel> <ComboBox x:Name="bars" Height="21" SelectedItem="{Binding Bar}"> <ComboBox.ItemTemplate> <DataTemplate> <Grid Background="LightBlue" Width="200" Height="20"> <TextBlock Text="{Binding Name}" /> </Grid> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> </StackPanel> </Window> 

如果您想进一步validation,您可以处理ComboBox上的SelectionChanged事件,并看到“select空项目”实际上在其SelectionChangedEventArgs中给出了一个空的数组AddedItems,并通过用鼠标select“Hello”来取消select空项目“给出一个RemovedItems的空数组。

那么最近我遇到了与ComboBox 值相同的问题。 我已经通过使用两个转换器解决了它:

  1. 对于ItemsSource属性:它通过在转换器参数中传递的任何值来replace集合中的值:

     class EnumerableNullReplaceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var collection = (IEnumerable)value; return collection .Cast<object>() .Select(x => x ?? parameter) .ToArray(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException(); } } 
  2. 对于SelectedValue属性:这个对于单个值有两个方法:

     class NullReplaceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value ?? parameter; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return value.Equals(parameter) ? null : value; } } 

使用示例:

 <ComboBox ItemsSource="{Binding MyValues, Converter={StaticResource EnumerableNullReplaceConverter}, ConverterParameter='(Empty)'}" SelectedValue="{Binding SelectedMyValue, Converter={StaticResource NullReplaceConverter}, ConverterParameter='(Empty)'}" /> 

结果:

在这里输入图像说明

注意:如果您绑定到ObservableCollection,那么您将失去更改通知。 你也不想在集合中有多个值。

我知道这个答案不是你所要求的(解释为什么它不适用于鼠标),但我认为前提是有缺陷的:

从我作为程序员和用户(而不是.NET)的angular度来看,select一个空值是一件坏事。 “空”应该是没有价值,而不是你select的东西。

如果你需要显式的不select某些东西,我会build议你提到的解决方法(“ – ”,“na”或“none”作为一个值),或者更好

  • 用checkbox包装combobox,可以取消选中以禁用combobox。 这从使用者的angular度和编程上来说都是最干净的devise。

我为这个问题得到了一个新的解决scheme。 “使用Mahapps”

  xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" <ComboBox x:Name="bars" **controls:TextBoxHelper.ClearTextButton="True"** DisplayMemberPath="Name" Height="21" SelectedItem="{Binding Bar}"/> 

在这里输入图像说明

在这里输入图像说明

您可以使用closuresbutton清除内容。

谢谢。

这可能不会完全解决你的答案,但希望它的方向是正确的:

  1. 你安装了SP1吗?

来自Scott Gu的博客:

  • NET 3.5 SP1包括几个数据绑定和编辑的改进
    WPF。 这些包括:
  • 在{{Binding}}expression式中支持StringFormat支持绑定值的简单格式
  • 新的交替行支持从ItemsControl派生的控件,这使得更容易在行上设置交替属性(例如:交替的背景颜色)
  • 可编辑控件中的空值进行更好的处理和转换支持将validation规则应用于整个绑定项目的项目级validation
  • MultiSelector支持处理多选和批量编辑的情况
  • IEditableCollectionView支持将数据控件连接到数据源,并以事务方式启用编辑/添加/删除项目
  • 绑定到IEnumerable数据源时的性能改进

对不起,如果我浪费了你的时间,这甚至没有closures..但我认为这个问题是inheritance自:

强types数据集的约束

NullValueDataSet在这里解释

但是,现在的.Net 3.5的SP1应该已经解决了这个问题。

我花了一天的时间find一个关于在combobox中select一个空值的问题的解决scheme,最后,最后我发现了一个在这个URL写的文章的解决scheme:

http://remyblok.tweakblogs.net/blog/7237/wpf-combo-box-with-empty-item-using-net-4-dynamic-objects.html

 public class ComboBoxEmptyItemConverter : IValueConverter { /// <summary> /// this object is the empty item in the combobox. A dynamic object that /// returns null for all property request. /// </summary> private class EmptyItem : DynamicObject { public override bool TryGetMember(GetMemberBinder binder, out object result) { // just set the result to null and return true result = null; return true; } } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // assume that the value at least inherits from IEnumerable // otherwise we cannot use it. IEnumerable container = value as IEnumerable; if (container != null) { // everything inherits from object, so we can safely create a generic IEnumerable IEnumerable<object> genericContainer = container.OfType<object>(); // create an array with a single EmptyItem object that serves to show en empty line IEnumerable<object> emptyItem = new object[] { new EmptyItem() }; // use Linq to concatenate the two enumerable return emptyItem.Concat(genericContainer); } return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } 

}

  <ComboBox ItemsSource="{Binding TestObjectCollection, Converter={StaticResource ComboBoxEmptyItemConverter}}" SelectedValue="{Binding SelectedID}" SelectedValuePath="ID" DisplayMemberPath="Name" /> 

尝试Binding.FallbackValue

从我打赌的6件事你不知道WPF中的数据绑定

我有同样的问题,我们做了一些工作,像添加一个值属性集合项目是这样的:

  public class Bar { public string Name { get; set; } public Bar Value { get { return String.IsNullOrEmpty(Name) ? null : this; } // you can define here your criteria for being null } } 

然后,而添加项目,而不是null我使用相同的对象:

  comboBox1.ItemsSource= new ObservableCollection<Bar> { new Bar(), new Bar { Name = "Hello" }, new Bar { Name = "World" } }; 

而不是selecteditem我把它绑定到selectedvalue:

 <ComboBox Height="23" Margin="25,40,133,0" DisplayMemberPath="Name" SelectedValuePath="Value" SelectedValue="{Binding Bar}" Name="comboBox1" VerticalAlignment="Top" /> 

我知道这不是一个完整的解决scheme,只是一个解决方法,我使用

ComboBox需要一个DataTemplate来显示这个项目,不pipe它有多简单。 DataTemplate的工作方式如下:从实例中获取一个值[path],例如

 bar1.Car.Color 

所以它不能从中获得价值

 null.Car.Color 

它会抛出一个空引用exception。 所以,null实例将不会显示。 但是颜色 – 如果它是一个引用types – 被允许为空,因为在这种情况下不会有exception。

只是一个猜测,但我认为这听起来很合理。

假设combobox使用“ListCollectionView”(lcv作为其实例)作为其项目集合,它应该是。 如果你是程序员,你会怎么做?

我将对键盘和鼠标进行响应。

一旦我得到键盘input,我使用

 lcv.MoveCurrentToNext(); 

要么

 lcv.MoveCurrentToPrevious(); 

所以,确保键盘运作良好。

然后我正在致力于鼠标input。 这就是问题所在。

  1. 我想听我的项目的“MouseClick”事件。 但可能,我的项目不生成,它只是一个占位符。 所以当用户点击这个占位符时,我什么也得不到。

  2. 如果我成功举办了活动,接下来是什么。 我会调用

    lcv.MoveCurrentTo(将selectedItem);

在我看来,这个“selectedItem”将是空的并不是一个可接受的参数。

无论如何,这只是猜测。 尽pipe我能够,但我没有时间去debugging。 我有一堆缺陷需要修复。 祝你好运。 🙂