具有空值的 WPF ComboBox SelectedValue 绑定显示为空白
WPF ComboBox SelectedValue binding with null value shows up blank
我在尝试将 2 个或更多 Comboboxes SelectedValue 绑定到 属性 时遇到问题,该 属性 为 null。
绑定到此 属性 的组合框中只有 1 个会显示实际值。
下面是我的 Xaml,我在其中使用 DataTemplate select 组合框来呈现 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值?
我可以更改其中任何一个的值,它们都将与 属性 中的值同步 - 如果我 select 1 然后返回 NULL,它们将全部显示 NULL。
好像只有初始值显示不正确
如果我避免使用 DataTemplate,绑定也可以。
有谁知道为什么 DAtaTemplate 会这样?
有趣的问题。
从根本上说,这似乎是您选择使用 null
作为可选值之一造成的。 null
当然,对于 C#、.NET 和 WPF 具有特殊含义。该问题还涉及 ComboBox
元素的初始化顺序。 SelectedValuePath
属性 初始化 after SelectedValue
属性.
这意味着当您的程序启动并创建 ComboBox
元素时,当 null
通过其绑定分配给 SelectedValue
属性 时, ComboBox
还没有足够的信息来处理该值作为合法项目选择。相反,它将其解释为根本没有选择。
为什么 last ComboBox
仍然按照您想要的方式进行初始化?我不太确定……我没有对此进行深入调查。我可以推测,但我猜对的几率似乎很低,所以我不会打扰。因为它是异常的,不一定符合预期的行为(基于上述,即使行为是 desired 行为)我将把它归结为 WPF 的众多 [=87] 之一=]. :)
我找到了几个解决该问题的方法:
- 不要使用
null
作为可选值。如果每个可选值都是非空值,则用于初始化每个元素的 SelectedValue
属性 的非空值将被保留,并且当 SelectedValuePath
被初始化时,当前选择的 ComboBox
设置正确。
- 不要使用
SelectedValuePath
。相反,只需绑定到 SelectedItem
并使用所需的 SelectableValue
class 实例(例如列表中的第一个实例)初始化 Value
属性。
- 在
ComboBox
的Loaded
事件中,刷新绑定目标。
前两个与您当前的设计存在重大差异。就个人而言,如果可能的话,我会选择其中之一。在我看来,使用 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
属性进行绑定是非常令人困惑的。例如,我会使用 SelectedValue
和 ItemValue
,分别表示 PropertyValueViewModel
class 和 SelectableValue
class。
我在尝试将 2 个或更多 Comboboxes SelectedValue 绑定到 属性 时遇到问题,该 属性 为 null。 绑定到此 属性 的组合框中只有 1 个会显示实际值。
下面是我的 Xaml,我在其中使用 DataTemplate select 组合框来呈现 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值? 我可以更改其中任何一个的值,它们都将与 属性 中的值同步 - 如果我 select 1 然后返回 NULL,它们将全部显示 NULL。 好像只有初始值显示不正确
如果我避免使用 DataTemplate,绑定也可以。 有谁知道为什么 DAtaTemplate 会这样?
有趣的问题。
从根本上说,这似乎是您选择使用 null
作为可选值之一造成的。 null
当然,对于 C#、.NET 和 WPF 具有特殊含义。该问题还涉及 ComboBox
元素的初始化顺序。 SelectedValuePath
属性 初始化 after SelectedValue
属性.
这意味着当您的程序启动并创建 ComboBox
元素时,当 null
通过其绑定分配给 SelectedValue
属性 时, ComboBox
还没有足够的信息来处理该值作为合法项目选择。相反,它将其解释为根本没有选择。
为什么 last ComboBox
仍然按照您想要的方式进行初始化?我不太确定……我没有对此进行深入调查。我可以推测,但我猜对的几率似乎很低,所以我不会打扰。因为它是异常的,不一定符合预期的行为(基于上述,即使行为是 desired 行为)我将把它归结为 WPF 的众多 [=87] 之一=]. :)
我找到了几个解决该问题的方法:
- 不要使用
null
作为可选值。如果每个可选值都是非空值,则用于初始化每个元素的SelectedValue
属性 的非空值将被保留,并且当SelectedValuePath
被初始化时,当前选择的ComboBox
设置正确。 - 不要使用
SelectedValuePath
。相反,只需绑定到SelectedItem
并使用所需的SelectableValue
class 实例(例如列表中的第一个实例)初始化Value
属性。 - 在
ComboBox
的Loaded
事件中,刷新绑定目标。
前两个与您当前的设计存在重大差异。就个人而言,如果可能的话,我会选择其中之一。在我看来,使用 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
属性进行绑定是非常令人困惑的。例如,我会使用 SelectedValue
和 ItemValue
,分别表示 PropertyValueViewModel
class 和 SelectableValue
class。