具有空值的 WPF ComboBox SelectedValue 绑定显示为空白

Posted

技术标签:

【中文标题】具有空值的 WPF ComboBox SelectedValue 绑定显示为空白【英文标题】:WPF ComboBox SelectedValue binding with null value shows up blank 【发布时间】:2015-09-10 00:21:33 【问题描述】:

我在尝试将 2 个或更多 Comboboxes SelectedValue 绑定到一个属性时遇到问题,该属性为空。 只有 1 个绑定到该属性的组合框会显示实际值。

下面是我的 Xaml,我在其中使用 DataTemplate 选择一个组合框来展示 viewModel。

Xaml:

<Window x:Class="Test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Test"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate DataType="x:Type local:PropertyValueViewModel">
        <ComboBox SelectedValue="Binding Value" ItemsSource="Binding SelectableValues" DisplayMemberPath="Description" SelectedValuePath="Value"/>
    </DataTemplate>
</Window.Resources>
<StackPanel>
    <Label Content="These uses template:"></Label>
    <ContentPresenter Content="Binding ValueSelector"></ContentPresenter>
    <ContentPresenter Content="Binding ValueSelector"></ContentPresenter>
    <ContentPresenter Content="Binding ValueSelector"></ContentPresenter>
</StackPanel>

以及背后的代码:

 public partial class MainWindow : Window

    public MainWindow()
    
        InitializeComponent();

        ValueSelector = new PropertyValueViewModel()
        
            SelectableValues = new List<SelectableValue>()
            
                new SelectableValue("NULL", null),
                new SelectableValue("1", 1)
            ,
            Value = null
        ;

        DataContext = this;
    

    public static readonly DependencyProperty ValueSelectorProperty = DependencyProperty.Register(
        "ValueSelector", typeof(PropertyValueViewModel), typeof(MainWindow), new PropertyMetadata(default(PropertyValueViewModel)));

    public PropertyValueViewModel ValueSelector
    
        get  return (PropertyValueViewModel)GetValue(ValueSelectorProperty); 
        set  SetValue(ValueSelectorProperty, value); 
    


/// <summary>
/// My viewModel
/// </summary>
public class PropertyValueViewModel

    public object Value  get; set; 
    public object SelectableValues  get; set; 


/// <summary>
/// The items in the combobox
/// </summary>
public class SelectableValue

    public SelectableValue(string header, object value)
    
        Value = value;
        Description = header;
    

    public object Value  get; set; 

    public string Description  get; set; 

现在我想知道为什么只有其中 1 个可以在启动时显示 NULL 值? 我可以更改其中任何一个中的值,它们都将与属性中的值同步 - 如果我选择 1 然后返回 NULL,它们都将显示 NULL。 似乎它唯一的初始值没有正确显示。

如果我避免使用 DataTemplate,绑定也可以。 有谁知道为什么 DATATemplate 会这样?

【问题讨论】:

【参考方案1】:

有趣的问题。

从根本上说,这似乎是由于您选择使用null 作为可选值之一。当然,null 对于 C#、.NET 和 WPF 具有特殊含义。问题还涉及到ComboBox 元素的初始化完成的顺序。 SelectedValuePath 属性在SelectedValue 属性之后被初始化

这意味着当您的程序正在启动并创建 ComboBox 元素时,当 null 通过其绑定分配给 SelectedValue 属性时,ComboBox 还没有足够的信息来处理它值作为合法的项目选择。相反,它会将其解释为根本没有选择。

为什么 last ComboBox 仍然按照您想要的方式初始化?我不太确定……我没有对此进行深入调查。我可以推测,但我猜对的几率似乎很低,所以我不会打扰。由于这是异常现象,不一定与预期行为一致(基于上述,即使该行为是期望的行为),我会将其归结为 WPF 的许多“怪癖”之一。 :)

我找到了几个解决这个问题的方法:

不要使用null 作为可选值。如果每个可选值都是非空值,则保留用于初始化每个元素的 SelectedValue 属性的非空值,当 SelectedValuePath 初始化时,ComboBox 的当前选择设置正确。 不要使用SelectedValuePath。相反,只需绑定到 SelectedItem 并使用所需的 SelectableValue 类实例(例如列表中的第一个实例)初始化 Value 属性。 在ComboBoxLoaded事件中,刷新绑定的目标。

前两个与您当前的设计有很大不同。就个人而言,如果可能的话,我会选择其中一个。在我看来,使用null 作为ComboBox 中的可选值存在明显的危险,这可能不是您遇到的唯一奇怪之处。从长远来看,如果继续使用null,这部分代码的维护成本可能会更高。

也就是说,第三个选项确实有效,如果幸运的话,使用null 的唯一真正危险在于初始化。我为该选项建议的解决方法如下所示:

XAML:

<DataTemplate DataType="x:Type local:PropertyValueViewModel">
    <ComboBox SelectedValue="Binding Value"
              ItemsSource="Binding SelectableValues"
              DisplayMemberPath="Description"
              SelectedValuePath="Value"
              Loaded="comboBox_Loaded"/>
</DataTemplate>

C#:

private void comboBox_Loaded(object sender, RoutedEventArgs e)

    ComboBox comboBox = (ComboBox)e.OriginalSource;

    BindingOperations.GetBindingExpression(comboBox, ComboBox.SelectedValueProperty)
                     .UpdateTarget();

这会强制 WPF 更新目标(即控件的 SelectedValue 属性)。由于此时SelectedValuePath 已设置,因此这次将null 分配给属性会正确更新ComboBox 的选定项。

顺便说一句,我强烈建议您消除模型中 Value 属性的名称的歧义。在单个 XAML 元素中有两个不同的 Value 属性用于绑定是非常令人困惑的。例如,PropertyValueViewModel 类和 SelectableValue 类分别使用 SelectedValueItemValue

【讨论】:

以上是关于具有空值的 WPF ComboBox SelectedValue 绑定显示为空白的主要内容,如果未能解决你的问题,请参考以下文章

Redshift:分析数据库中所有表中具有空值的所有列

WPF中让Combobox具有查找功能

具有在 XAML 中定义的选项的数据绑定 WPF ComboBox?

在火花中删除空值列

wpf combobox 关闭窗口后,再次调用不显示已经选择的值?

具有默认空值的 AvrologicalType 'date'