ValueTuple 不支持 DisplayMemberPath。组合框,WPF
ValueTuple does not support DisplayMemberPath. Combobox, WPF
我有一个组合框,想将其 ItemsSource 绑定到 IEnumerable<(string,string)>
。如果我不设置 DisplayMemberPath,那么它会起作用,并且会在下拉区域中显示在项目中调用 ToString()
的结果。然而,当我设置 DisplayMemberPath="Item1"
时,它不再显示任何内容。我制作了以下示例,您可能会在其中看到如果我使用经典 Tuple
类型,它会按预期工作。
调试时我检查了 valuetuple 也有 Item1 和 Item2 作为属性。
我的XAML:
<Window x:Class="TupleBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="MainWindow_OnLoaded"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox x:Name="TupleCombo" Grid.Row="0" VerticalAlignment="Center"
DisplayMemberPath="Item1" />
<ComboBox x:Name="ValueTupleCombo" Grid.Row="1" VerticalAlignment="Center"
DisplayMemberPath="Item1" />
</Grid>
</Window>
还有我的代码隐藏:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace TupleBindingTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private IEnumerable<Tuple<string, string>> GetTupleData()
{
yield return Tuple.Create("displayItem1", "valueItem1");
yield return Tuple.Create("displayItem2", "valueItem2");
yield return Tuple.Create("displayItem3", "valueItem3");
}
private IEnumerable<(string, string)> GetValueTupleData()
{
yield return ( "displayItem1", "valueItem1");
yield return ("displayItem2", "valueItem2");
yield return ("displayItem3", "valueItem3");
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
TupleCombo.ItemsSource = GetTupleData();
ValueTupleCombo.ItemsSource = GetValueTupleData();
}
}
}
在运行时,此示例将在第一个组合框中正确显示数据,但在第二个组合框中不显示任何数据。
为什么会这样?
这是因为 DisplayMemberPath
在内部为每个项目的模板设置了与指定路径的绑定。所以设置 DisplayMemberPath="Item1"
基本上是 shorthand 用于设置以下 ComboBox.ItemTemplate
:
<DataTemplate>
<ContentPresenter Content="{Binding Item1}" />
</DataTemplate>
现在 WPF 仅支持绑定到属性。这就是为什么它在您使用 Tuple
s 时工作正常 - 因为它的成员是 properties,也是为什么它不能与 ValueTuple
s 一起工作 - 因为它的成员是字段.
但是在您的特定情况下,由于您仅将这些集合用作绑定源,因此您可以使用 匿名类型 来实现您的目标(其成员也是 属性),例如:
private IEnumerable<object> GetTupleData()
{
yield return new { Label = "displayItem1", Value = "valueItem1" };
yield return new { Label = "displayItem2", Value = "valueItem2" };
yield return new { Label = "displayItem3", Value = "valueItem3" };
}
然后你可以设置你的ComboBox
:
<ComboBox DisplayMemberPath="Label" SelectedValuePath="Value" (...) />
我有一个组合框,想将其 ItemsSource 绑定到 IEnumerable<(string,string)>
。如果我不设置 DisplayMemberPath,那么它会起作用,并且会在下拉区域中显示在项目中调用 ToString()
的结果。然而,当我设置 DisplayMemberPath="Item1"
时,它不再显示任何内容。我制作了以下示例,您可能会在其中看到如果我使用经典 Tuple
类型,它会按预期工作。
调试时我检查了 valuetuple 也有 Item1 和 Item2 作为属性。
我的XAML:
<Window x:Class="TupleBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="MainWindow_OnLoaded"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox x:Name="TupleCombo" Grid.Row="0" VerticalAlignment="Center"
DisplayMemberPath="Item1" />
<ComboBox x:Name="ValueTupleCombo" Grid.Row="1" VerticalAlignment="Center"
DisplayMemberPath="Item1" />
</Grid>
</Window>
还有我的代码隐藏:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
namespace TupleBindingTest
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private IEnumerable<Tuple<string, string>> GetTupleData()
{
yield return Tuple.Create("displayItem1", "valueItem1");
yield return Tuple.Create("displayItem2", "valueItem2");
yield return Tuple.Create("displayItem3", "valueItem3");
}
private IEnumerable<(string, string)> GetValueTupleData()
{
yield return ( "displayItem1", "valueItem1");
yield return ("displayItem2", "valueItem2");
yield return ("displayItem3", "valueItem3");
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
TupleCombo.ItemsSource = GetTupleData();
ValueTupleCombo.ItemsSource = GetValueTupleData();
}
}
}
在运行时,此示例将在第一个组合框中正确显示数据,但在第二个组合框中不显示任何数据。
为什么会这样?
这是因为 DisplayMemberPath
在内部为每个项目的模板设置了与指定路径的绑定。所以设置 DisplayMemberPath="Item1"
基本上是 shorthand 用于设置以下 ComboBox.ItemTemplate
:
<DataTemplate>
<ContentPresenter Content="{Binding Item1}" />
</DataTemplate>
现在 WPF 仅支持绑定到属性。这就是为什么它在您使用 Tuple
s 时工作正常 - 因为它的成员是 properties,也是为什么它不能与 ValueTuple
s 一起工作 - 因为它的成员是字段.
但是在您的特定情况下,由于您仅将这些集合用作绑定源,因此您可以使用 匿名类型 来实现您的目标(其成员也是 属性),例如:
private IEnumerable<object> GetTupleData()
{
yield return new { Label = "displayItem1", Value = "valueItem1" };
yield return new { Label = "displayItem2", Value = "valueItem2" };
yield return new { Label = "displayItem3", Value = "valueItem3" };
}
然后你可以设置你的ComboBox
:
<ComboBox DisplayMemberPath="Label" SelectedValuePath="Value" (...) />