wpf - 在 MVVM 中取消选择 ComboBoxItems

标签 wpf mvvm

我正在使用标准的 wpf/mvvm 应用程序,我将组合框绑定(bind)到 ViewModel 上的集合。

我需要能够从下拉列表中取消选择一个项目。意思是,用户应该能够选择一些东西,然后决定他们想要取消选择它(选择无)。问题是我的绑定(bind)集合中没有空元素

我最初的想法只是在集合中插入一个新项目,这将导致集合顶部有一个空项目。

虽然这是一个 hack,但它会影响在 View 模型上使用该集合的所有代码。

例如,如果有人要写

_myCollection.Frist(o => o.Name == "foo") 

这将引发空引用异常。

可能的解决方法是:
_myCollection.Where(o => o != null).First(o => o.Name == "foo");

这将起作用,但无法确保该集合的任何 future 使用不会导致任何中断。

什么是能够添加空项目以便用户取消选择的好模式/解决方案。 (我也知道 CollectionView 结构,但对于如此简单的事情来说,这似乎有点过头了)

更新

接受@hbarck 的建议并实现了 CompositeCollection(快速概念证明)
    public CompositeCollection MyObjects {
        get {
            var col = new CompositeCollection();

            var cc1 = new CollectionContainer();
            cc1.Collection = _actualCollection;

            var cc2 = new CollectionContainer();
            cc2.Collection = new List<MyObject>() { null }; // PROBLEM

            col.Add(cc2);
            col.Add(cc1);
            return col;
        }
    }

此代码适用于现有的绑定(bind)(包括 SelectedItem),这很棒。

一个问题是,如果项目完全为空,则在选择它时永远不会调用 SelectedItem setter .

如果我将这一行修改为:
            cc2.Collection = new List<MyObject>() { new MyObject() }; // PROBLEM

调用了setter,但现在我选择的项目只是一个基本的初始化类而不是null..我可以在setter中添加一些代码来检查/重置,但这并不好。

最佳答案

我认为最简单的方法是使用 CompositeCollection。只需将您的集合附加到另一个仅包含空项(null 或占位符对象,无论您需要什么)的集合,然后将 CompositeCollection 设置为 ComboBox 的 ItemsSource。这可能是它的目的。

更新:

事实证明这比我最初想象的要复杂,但实际上,我想出了这个解决方案:

<Window x:Class="ComboBoxFallbackValue"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:TestWpfDataBinding"
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    xmlns:w="clr-namespace:System.Windows;assembly=WindowsBase"
Title="ComboBoxFallbackValue" Height="300" Width="300">
<Window.Resources>
    <t:TestCollection x:Key="test"/>
    <CompositeCollection x:Key="MyItemsSource">
        <x:Static Member="t:TestCollection.NullItem"/>
        <CollectionContainer Collection="{Binding Source={StaticResource test}}"/>
    </CompositeCollection>
    <t:TestModel x:Key="model"/>
    <t:NullItemConverter x:Key="nullItemConverter"/>
</Window.Resources>
<StackPanel>
    <ComboBox x:Name="cbox" ItemsSource="{Binding Source={StaticResource MyItemsSource}}" IsEditable="true" IsReadOnly="True" Text="Select an Option" SelectedItem="{Binding Source={StaticResource model}, Path=TestItem, Converter={StaticResource nullItemConverter}, ConverterParameter={x:Static t:TestCollection.NullItem}}"/>
    <TextBlock Text="{Binding Source={StaticResource model}, Path=TestItem, TargetNullValue='Testitem is null'}"/>
</StackPanel>

基本上,该模式是您声明用作项目的类的单例 NullInstance,并在设置 VM 属性时使用将这个实例转换为 null 的 Converter。转换器可以通用写,像这样(是VB,希望你不要介意):
Public Class NullItemConverter
Implements IValueConverter

Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
    If value Is Nothing Then
        Return parameter
    Else
        Return value
    End If
End Function

Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
    If value Is parameter Then
        Return Nothing
    Else
        Return value
    End If
End Function

结束类

由于您可以重用转换器,因此您可以在 XAML 中进行设置;在代码中唯一需要做的就是提供单例 NullItem。

关于wpf - 在 MVVM 中取消选择 ComboBoxItems,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12644140/

相关文章:

c# - 使用 WPF 获取工具包样式窗口

c# - 更新/使用来自另一个 ViewModel 的变量

C# WPF 在 Canvas 上选择用户控件

c# - 当 ItemsSource 更改时 ComboBox 不更新

wpf - 仅在 WPF 中的 ShowDialog() 之后设置 DialogResult

c# - "Enable Debugging of Unmanaged Code"在哪里可以在系统运行时编辑代码?

c# - 如何将 Entity Framework ICollection 更改为 ObservableCollection?

mvvm - 将 MvxCommand 与 CommandParameter 绑定(bind)一起使用

c# - 无法在列表框中绑定(bind)命令

c# - 使用 Unity/Prism/MVVM 的 ObjectContext 构造函数注入(inject)