且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

绑定字典<T>到 WPF 列表框

更新时间:2021-12-25 02:33:57

在项目控件上设置 ItemsSource 会创建到源对象的枚举器的绑定.Dictionary 的枚举数是 IEnumerable> 类型.所以在你的item模板中,你可以绑定到KeyValue属性,使用路径语法获取key和value的具体属性.

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.

这是一个例子.首先是创建和填充字典并将其添加到资源字典的代码(有很多不同的方法可以将字典公开给数据绑定;这个很简单):

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; }
        }
    }
}

现在用于填充 ListBox 的 XAML(虽然 ListView 会更容易,因为您不必定义如此复杂的模板以使其看起来更漂亮):

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):

<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>

ListView 的 XAML 更简单,并且显示更容易启动:

The XAML for a ListView is a lot simpler, and displays more nicely to boot:

<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>

回答您的后续问题:

我推荐 Adam Nathan 的 Windows Presentation Foundation Unleashed.带有面板的布局一章非常详细地解释了网格的工作原理.Grid 在很多方面都非常违反直觉.您认为您希望创建一个包含许多项目的单个 Grid,但 Grid 中的行数和列数不是动态的.因此,您要做的是为每个项目创建一个 Grid,然后使用共享大小功能确保每个 Grid 中的列大小相同.ListView 有它自己的怪癖,但对于常见的在网格中显示多个项目"用例来说,它要简单得多.

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.

DynamicResource 是一个与 StaticResource 很相似的标记扩展.不同之处在于,当 XAML 解析器在解析 StaticResource 时解析它 - 如果引用的资源不在资源字典中,则会引发异常.DynamicResource 如果稍后将项目添加到字典中,则解析引用.这有一点性能成本,但在大多数情况下可以忽略不计.如果您使用 StaticResource,我发布的代码可以工作,因为 XAML 在 InitializeComponent 中被解析.但我不喜欢记住这一点,所以我默认使用 DynamicResource 如果我绑定到我在代码中添加到资源字典中的东西并且不用担心是否它是在解析 XAML 之前或之后创建的.

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.

至于工具箱:也许我会在 VS2010 中开始使用它,但我发现 2008 年的工具箱出现了无法使用的问题.反正也不是很有用.我几乎所有的布局工作都是在编辑器中完成的,有些是在 Kaxaml 中完成的.我认为 2008 年的可视化编辑器实际上让 WPF 的学习变得更加困难,因为它在我和 XAML 之间强加了一个抽象层(它本身就是我和 WPF 对象模型之间的一个抽象层).而且它不是一个很好的抽象层:在我看来,决定什么应该隐藏什么应该可见的设计决策不是正确的.也太坑爹了.

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.