Given a dictionary of <string, Drink>
, how would you bind the dictionary.Values
to a WPF ListBox, so that the items use the .Name
property?
给定一本
struct Drink
{
public string Name { get; private set; }
public int Popularity { get; private set; }
public Drink ( string name, int popularity )
: this ( )
{
this.Name = name;
this.Popularity = popularity;
}
}
2 个解决方案
#1
43
Setting the ItemsSource
on an items control creates a binding to the enumerator for the source object. The enumerator of a Dictionary<T1, T2>
is of type IEnumerable<KeyValuePair<T1, T2>>
. So in your item template, you can bind to the Key
and Value
properties, and use the path syntax to get specific properties of the key and value.
在项目控件上设置ItemsSource将为源对象创建一个绑定到枚举器。字典的枚举数
Here's an example. First the code that creates and populates the dictionary and adds it to the resource dictionary (there are lots of different ways you can expose the dictionary to data binding; this one's simple):
这是一个例子。首先,创建并填充字典并将其添加到资源字典的代码(有许多不同的方法可以将字典暴露给数据绑定;这个很简单):
namespace WpfApplication17
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
Dictionary<string, Drink> d = new Dictionary<string, Drink>();
d.Add("A", new Drink("Nehi", 0));
d.Add("B", new Drink("Moxie", 1));
d.Add("C", new Drink("Vernor's", 2));
d.Add("D", new Drink("Canfield's", 3));
Resources["Drinks"] = d;
InitializeComponent();
}
public class Drink
{
public Drink(string name, int popularity)
{
Name = name;
Popularity = popularity;
}
public string Name { get; set; }
public int Popularity { get; set; }
}
}
}
Now the XAML for populating a ListBox
(though a ListView
would be easier, because you wouldn't have to define a template this complicated to make it look nice):
现在,XAML填充了一个列表框(虽然ListView会更容易,因为您不必定义这个复杂的模板来让它看起来很漂亮):
<Window x:Class="WpfApplication17.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Grid Margin="10">
<ListBox ItemsSource="{DynamicResource Drinks}" Grid.IsSharedSizeScope="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Key" />
<ColumnDefinition SharedSizeGroup="Name" />
<ColumnDefinition SharedSizeGroup="Popularity" />
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Text="{Binding Key}" Grid.Column="0"/>
<TextBlock Margin="2" Text="{Binding Value.Name}" Grid.Column="1"/>
<TextBlock Margin="2" Text="{Binding Value.Popularity}" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
The XAML for a ListView
is a lot simpler, and displays more nicely to boot:
用于ListView的XAML要简单得多,而且显示得更漂亮:
<ListView ItemsSource="{DynamicResource Drinks}">
<ListView.View>
<GridView>
<GridViewColumn Header="Key"
DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding Value.Name}" />
<GridViewColumn Header="Popularity"
DisplayMemberBinding="{Binding Value.Popularity}" />
</GridView>
</ListView.View>
</ListView>
To answer your follow-up questions:
回答你的后续问题:
I recommend Adam Nathan's Windows Presentation Foundation Unleashed. The chapter on layout with panels explains how the Grid works in considerable detail. The Grid
's pretty counter-intuitive in a lot of ways. You think that you'd want to create a single Grid
that contains many items, but the number of rows and columns in a Grid
isn't dynamic. So what you do instead is create a Grid
for each item, and then use the shared-size functionality to make sure that the columns in each Grid
are the same size. The ListView
has quirks of its own, but it's a lot more straightforward for the common "display multiple items in a grid" use case.
我推荐Adam Nathan的Windows Presentation Foundation。关于布局的章节介绍了网格如何工作的相当详细。网格在很多方面都很反直觉。您认为您希望创建包含许多项的单个网格,但是网格中的行数和列数不是动态的。因此,您要做的是为每个项目创建一个网格,然后使用共享大小的功能来确保每个网格中的列都是相同的大小。ListView有它自己的特性,但是对于公共“在网格中显示多个项目”用例来说,它更加直观。
DynamicResource
is a markup extension that works a lot like StaticResource
. The difference is that when the XAML parser resolves StaticResource
as it parses it - if the referenced resource isn't in the resource dictionary, it throws an exception. DynamicResource
resolves the reference if the item gets added to the dictionary later. There's a bit of a performance cost to this, but it's negligible in most cases. The code I posted works if you use StaticResource
, because the XAML gets parsed in InitializeComponent
. But I don't like having to remember that, so I use DynamicResource
by default if I'm binding to something that I'm adding to the resource dictionary in code and just don't worry about whether it's being created before or after the XAML gets parsed.
DynamicResource是一个标记扩展,它很像StaticResource。区别在于,当XAML解析器解析StaticResource时,当它解析它时——如果引用的资源不在资源字典中,它会抛出一个异常。如果稍后将该条目添加到字典中,DynamicResource将解析引用。这有一点性能成本,但在大多数情况下是可以忽略不计的。如果您使用StaticResource,那么我发布的代码会起作用,因为XAML在InitializeComponent中被解析。但是我不喜欢记住这个,所以我在默认情况下使用DynamicResource如果我绑定到我在代码中添加到资源字典的东西,只是不用担心它是在XAML被解析之前还是之后创建的。
And as for the toolbox: Maybe I'll start using that in VS2010, but I find the one in 2008 unusably buggy. And not very useful anyway. I do almost all of my layout work in the editor, and some in Kaxaml. I think the visual editor in 2008 actually made learning WPF harder, because it imposed an abstraction layer between me and the XAML (which is itself an abstraction layer between me and the WPF object model). And it's not a very good abstraction layer: the design decisions that went into deciding what should be hidden and what should be visible aren't, it seems to me, the right ones. Also it's buggy as hell.
至于工具箱:也许我将在2010年开始使用它,但我发现2008年的那辆车是不可用的。反正也没什么用。在编辑器中,我几乎做了所有的布局工作,还有一些在Kaxaml。我认为2008年的可视化编辑器实际上使学习WPF变得更加困难,因为它在我和XAML之间强加了一个抽象层(它本身就是我和WPF对象模型之间的抽象层)。这并不是一个很好的抽象层:决定什么应该隐藏的设计决策,什么应该是可见的,在我看来是正确的。它也像地狱一样。
#2
1
ListBox.DisplayMemberPath = "Name";
列表框。DisplayMemberPath =“名称”;
That will tell the listbox to use the 'Name' property of the DataContext
这将告诉listbox使用DataContext的“Name”属性。
#1
43
Setting the ItemsSource
on an items control creates a binding to the enumerator for the source object. The enumerator of a Dictionary<T1, T2>
is of type IEnumerable<KeyValuePair<T1, T2>>
. So in your item template, you can bind to the Key
and Value
properties, and use the path syntax to get specific properties of the key and value.
在项目控件上设置ItemsSource将为源对象创建一个绑定到枚举器。字典的枚举数
Here's an example. First the code that creates and populates the dictionary and adds it to the resource dictionary (there are lots of different ways you can expose the dictionary to data binding; this one's simple):
这是一个例子。首先,创建并填充字典并将其添加到资源字典的代码(有许多不同的方法可以将字典暴露给数据绑定;这个很简单):
namespace WpfApplication17
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
Dictionary<string, Drink> d = new Dictionary<string, Drink>();
d.Add("A", new Drink("Nehi", 0));
d.Add("B", new Drink("Moxie", 1));
d.Add("C", new Drink("Vernor's", 2));
d.Add("D", new Drink("Canfield's", 3));
Resources["Drinks"] = d;
InitializeComponent();
}
public class Drink
{
public Drink(string name, int popularity)
{
Name = name;
Popularity = popularity;
}
public string Name { get; set; }
public int Popularity { get; set; }
}
}
}
Now the XAML for populating a ListBox
(though a ListView
would be easier, because you wouldn't have to define a template this complicated to make it look nice):
现在,XAML填充了一个列表框(虽然ListView会更容易,因为您不必定义这个复杂的模板来让它看起来很漂亮):
<Window x:Class="WpfApplication17.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300">
<Grid Margin="10">
<ListBox ItemsSource="{DynamicResource Drinks}" Grid.IsSharedSizeScope="True">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Key" />
<ColumnDefinition SharedSizeGroup="Name" />
<ColumnDefinition SharedSizeGroup="Popularity" />
</Grid.ColumnDefinitions>
<TextBlock Margin="2" Text="{Binding Key}" Grid.Column="0"/>
<TextBlock Margin="2" Text="{Binding Value.Name}" Grid.Column="1"/>
<TextBlock Margin="2" Text="{Binding Value.Popularity}" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
The XAML for a ListView
is a lot simpler, and displays more nicely to boot:
用于ListView的XAML要简单得多,而且显示得更漂亮:
<ListView ItemsSource="{DynamicResource Drinks}">
<ListView.View>
<GridView>
<GridViewColumn Header="Key"
DisplayMemberBinding="{Binding Key}" />
<GridViewColumn Header="Name"
DisplayMemberBinding="{Binding Value.Name}" />
<GridViewColumn Header="Popularity"
DisplayMemberBinding="{Binding Value.Popularity}" />
</GridView>
</ListView.View>
</ListView>
To answer your follow-up questions:
回答你的后续问题:
I recommend Adam Nathan's Windows Presentation Foundation Unleashed. The chapter on layout with panels explains how the Grid works in considerable detail. The Grid
's pretty counter-intuitive in a lot of ways. You think that you'd want to create a single Grid
that contains many items, but the number of rows and columns in a Grid
isn't dynamic. So what you do instead is create a Grid
for each item, and then use the shared-size functionality to make sure that the columns in each Grid
are the same size. The ListView
has quirks of its own, but it's a lot more straightforward for the common "display multiple items in a grid" use case.
我推荐Adam Nathan的Windows Presentation Foundation。关于布局的章节介绍了网格如何工作的相当详细。网格在很多方面都很反直觉。您认为您希望创建包含许多项的单个网格,但是网格中的行数和列数不是动态的。因此,您要做的是为每个项目创建一个网格,然后使用共享大小的功能来确保每个网格中的列都是相同的大小。ListView有它自己的特性,但是对于公共“在网格中显示多个项目”用例来说,它更加直观。
DynamicResource
is a markup extension that works a lot like StaticResource
. The difference is that when the XAML parser resolves StaticResource
as it parses it - if the referenced resource isn't in the resource dictionary, it throws an exception. DynamicResource
resolves the reference if the item gets added to the dictionary later. There's a bit of a performance cost to this, but it's negligible in most cases. The code I posted works if you use StaticResource
, because the XAML gets parsed in InitializeComponent
. But I don't like having to remember that, so I use DynamicResource
by default if I'm binding to something that I'm adding to the resource dictionary in code and just don't worry about whether it's being created before or after the XAML gets parsed.
DynamicResource是一个标记扩展,它很像StaticResource。区别在于,当XAML解析器解析StaticResource时,当它解析它时——如果引用的资源不在资源字典中,它会抛出一个异常。如果稍后将该条目添加到字典中,DynamicResource将解析引用。这有一点性能成本,但在大多数情况下是可以忽略不计的。如果您使用StaticResource,那么我发布的代码会起作用,因为XAML在InitializeComponent中被解析。但是我不喜欢记住这个,所以我在默认情况下使用DynamicResource如果我绑定到我在代码中添加到资源字典的东西,只是不用担心它是在XAML被解析之前还是之后创建的。
And as for the toolbox: Maybe I'll start using that in VS2010, but I find the one in 2008 unusably buggy. And not very useful anyway. I do almost all of my layout work in the editor, and some in Kaxaml. I think the visual editor in 2008 actually made learning WPF harder, because it imposed an abstraction layer between me and the XAML (which is itself an abstraction layer between me and the WPF object model). And it's not a very good abstraction layer: the design decisions that went into deciding what should be hidden and what should be visible aren't, it seems to me, the right ones. Also it's buggy as hell.
至于工具箱:也许我将在2010年开始使用它,但我发现2008年的那辆车是不可用的。反正也没什么用。在编辑器中,我几乎做了所有的布局工作,还有一些在Kaxaml。我认为2008年的可视化编辑器实际上使学习WPF变得更加困难,因为它在我和XAML之间强加了一个抽象层(它本身就是我和WPF对象模型之间的抽象层)。这并不是一个很好的抽象层:决定什么应该隐藏的设计决策,什么应该是可见的,在我看来是正确的。它也像地狱一样。
#2
1
ListBox.DisplayMemberPath = "Name";
列表框。DisplayMemberPath =“名称”;
That will tell the listbox to use the 'Name' property of the DataContext
这将告诉listbox使用DataContext的“Name”属性。