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;
}
}
Best Answer
Setting the
ItemsSource
on an items control creates a binding to the enumerator for the source object. The enumerator of aDictionary<T1, T2>
is of typeIEnumerable<KeyValuePair<T1, T2>>
. So in your item template, you can bind to theKey
andValue
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):
Now the XAML for populating a
ListBox
(though aListView
would be easier, because you wouldn't have to define a template this complicated to make it look nice):The XAML for a
ListView
is a lot simpler, and displays more nicely to boot: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 singleGrid
that contains many items, but the number of rows and columns in aGrid
isn't dynamic. So what you do instead is create aGrid
for each item, and then use the shared-size functionality to make sure that the columns in eachGrid
are the same size. TheListView
has quirks of its own, but it's a lot more straightforward for the common "display multiple items in a grid" use case.DynamicResource
is a markup extension that works a lot likeStaticResource
. The difference is that when the XAML parser resolvesStaticResource
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 useStaticResource
, because the XAML gets parsed inInitializeComponent
. But I don't like having to remember that, so I useDynamicResource
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.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.