Beginner – confused about binding and resources in WPF

First, an overall comment:

WPF is hard to learn. It’s hard to learn because there are several different fundamentally new concepts that you have to get your head around at the same time. The struggle that you’re having right now is that you’re trying to learn at least three different things at once:

  • How the XamlReader (and particularly markup extensions) deserializes XAML into objects.
  • How the FrameworkElement‘s resource dictionaries work.
  • How data binding works.

Something like this:

<TextBox Text="{Binding Source={StaticResource MyPerson}, Path=Name}"/>

is engaging (at least) three very different technologies at the same time. Those technologies are all designed to be as flexible as possible, which only makes them more confusing to the beginner. The idea that a binding source can be just about anything: that’s hard to grasp. The idea that a markup extension is a special kind of serialization format that supports recursion: simple enough to understand in principle, but a little baffling when you first start working with real-world examples. The idea that a resource dictionary can contain just about anything, and that the resource searching algorithm essentially makes resources inheritable: again, pretty simple in concept, but easy to lose the thread of when you’re trying to figure out data binding and XAML at the same time.

It’s frustrating, because something that’s conceptually simple – “I want to bind this control to a property of an object that I’ve created” – requires that you understand a great many things before you can actually express it in XAML.

The only solution is to be patient, and to make sure you understand things at the lowest level possible. When you see this:

{StaticResource MyPerson}

you should be able to think, “That’s going to invoke the StaticResource markup extension handler, which retrieves an object from a resource dictionary using the key MyPerson when the XAML is deserialized.

It’s extremely challenging at first. I’ve been developing software professionally for 35 years, and I’ve found WPF to be the most challenging technology platform that I’ve ever learned by a considerable margin. But all of this stuff is hard to learn because it’s incredibly functional and flexible. And the payoff of learning it is huge.

To address a couple of issues that karmicpuppet didn’t:

From my experience in MFC [resources] were icons, strings, etc.

That hasn’t changed. You can still create resource files in WPF and load them into objects at runtime. There are lots of different ways of doing this – you can create resources in the resource editor and load them via the Properties.Resources object, you can add image files (for instance) to the project, have them compiled as resources, and load them using their URI, and there are plenty of other ways that I don’t know about.

The resources available to FrameworkElements via their resource dictionaries are a different thing. Well, sort of. Here’s an example:

<Window.Resources>
   <Image x:Key="MyImage" Source="images/myimage.png"/>
</Window.Resources>

This creates an Image object and adds it to the Window‘s resource dictionary with a key of MyImage You can then reference that object via the StaticResource markup extension in XAML, or the FindResource method in code.

Setting the Source attribute on the Image element in XAML also makes the XamlReader use the ResourceManager to read the image data from the project’s compiled resources at runtime when it creates the Image object.

In practice, this is nowhere near as confusing as it is when you’re first learning WPF. I never get resources that ResourceManager loads and resources stored in resource dictionaries mixed up.

And when exactly is that object created?

Any object defined by a XAML element is created when the XamlReader reads the element. So this:

<Window.Resources>
   <local:Person x:Key="MyPerson"/>
</Window.Resources>

instantiates a new Person object and adds it to the Window‘s resource dictionary with a key of MyPerson. It’s exactly equivalent to doing this in the Window‘s code-behind:

AddResource("MyPerson", new Person());

So why don’t you just do it in code-behind? Two reasons:

First, it’s consistent. If you define all your resources in XAML, you only need to look in XAML files to find what your resources are. If you define them in both XAML and code-behind, you have to look in two places.

Second, the IDE knows about resources that you define in XAML. If you type

<TextBox Text="{Binding {StaticResource MyPerson}, Path=Name}"/>

in your XAML, the IDE will let you know if you haven’t defined, somewhere in the hierarchy of resource dictionaries, a resource whose key is MyPerson. But it doesn’t know about resources that you’ve added in code, and so even though the resource may actually be findable at runtime, the IDE will report it as a problem.

Leave a Comment