为什么我不能在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 空值相同的问题。 我已经通过使用两个转换器解决了它:
-
对于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(); } }
-
对于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清除内容。
谢谢。
这可能不会完全解决你的答案,但希望它的方向是正确的:
- 你安装了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:
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。 这就是问题所在。
-
我想听我的项目的“MouseClick”事件。 但可能,我的项目不生成,它只是一个占位符。 所以当用户点击这个占位符时,我什么也得不到。
-
如果我成功举办了活动,接下来是什么。 我会调用
lcv.MoveCurrentTo(将selectedItem);
在我看来,这个“selectedItem”将是空的并不是一个可接受的参数。
无论如何,这只是猜测。 尽pipe我能够,但我没有时间去debugging。 我有一堆缺陷需要修复。 祝你好运。 🙂