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

7

当我试图将两个或多个组合框的SelectedValue绑定到一个空属性时,出现了问题。

只有一个绑定到此属性的组合框会显示实际值。

以下是我的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; }
}

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

如果我避免使用 DataTemplate,则绑定也有效。 有人知道为什么 DataTemplate 会以这种方式运作吗?

1个回答

5
有趣的问题。
从根本上讲,这似乎是由于您选择使用null作为可选值之一所致。当然,对于C#、.NET和WPF来说,null具有特殊含义。问题还涉及初始化ComboBox元素的顺序。SelectedValuePath属性是在SelectedValue属性之后初始化的。
这意味着,当您的程序启动并创建ComboBox元素时,当通过绑定将null分配给SelectedValue属性时,ComboBox还没有足够的信息来将该值处理为合法的项目选择。相反,它将其解释为未选择任何内容。
为什么最后一个ComboBox仍然以您想要的方式进行初始化?我不是很确定...我没有深入调查过。我可以猜测,但我猜测正确的机会似乎很低,所以我不会费心去猜测。既然它是异常而不是符合预期行为(基于以上内容,即使行为是期望的行为),我会把它归结为WPF的许多“怪癖”。 :)
我发现了几个解决方法:
1. 不要使用null作为可选值。如果每个可选值都是非null的,则用于初始化每个元素的SelectedValue属性的非null值将被保留,并且当SelectedValuePath初始化时,ComboBox的当前选择将被正确设置。
2. 不要使用SelectedValuePath。而是绑定到SelectedItem,并使用所需的SelectableValue类实例(例如列表中的第一个)初始化Value属性。
3. 在ComboBox的Loaded事件中,刷新绑定的目标。
前两个与您当前的设计有很大不同。个人而言,如果可能的话,我会选择其中之一。在我的看来,在ComboBox中使用null作为可选值存在明显的危险,这可能不是您遇到的唯一的奇怪现象。从长远来看,如果您继续使用null,则代码的此部分的维护成本可能会更高。
话虽如此,第三个选项确实有效,如果您幸运的话,使用null的唯一真正危险的地方就在初始化时。我提议的解决方法如下:
<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等名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接