具有null值的WPF组合框SelectedValue绑定显示为空

本文关键字:绑定 显示 SelectedValue null 值的 WPF 组合 具有 | 更新日期: 2023-09-27 17:59:11

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

下面是我的Xaml,我使用DataTemplate选择一个组合框来表示视图模型。

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为什么会这样做吗?

具有null值的WPF组合框SelectedValue绑定显示为空

有趣的问题。

从根本上讲,这似乎是由于您选择使用null作为可选值之一而导致的。当然,null对于C#有着特殊的意义。NET和WPF。该问题还涉及对ComboBox元素进行初始化的顺序。SelectedValuePath属性在SelectedValue属性之后初始化

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

为什么最后一个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属性是非常令人困惑的。例如,我将分别使用SelectedValueItemValue作为PropertyValueViewModel类和SelectableValue类。