Dependency Properties in WPF
If you've been putting off mastering dependency properties, this is your chance
If you've always wanted to know what dependency properties are for, and how to use them, you're five minutes away from your goal.
Coding time: 5 minutes.
Windows Presentation Foundation (WPF) is Microsoft's replacement for the WinForms designer, and properties are the connective tissue of WPF applications. Binding is used to retrieve values from public properties of ViewModels and display them in forms - sorry, Views. Gotta use the right word.
Properties can also be used to call methods in the ViewModel, since you can run code while either getting or setting a property's value. In my Article 607, I showed how binding the text of a ComboBox to a ViewModel property with a method call in its setter could launch a LINQ query whose WHERE clause used the text property of the ComboBox as a parameter to return matching customers. I've seen setters with dozens of lines of code.
My Dropshadow Form Title UserControl
But properties can't always do everything you need. I had heard of dependency properties, but didn't really understand why I needed them. And the code look so strange that it kind of put me off. I don't know why they're so shrouded in mystery. Time to demystify them.
I needed a form title that would make it easy to give my forms a consistent look. So, I built a UserControl to display a nicely styled title on my application's forms. I added a gradient fill and a <shadow> tag. To allow the developer to set the title, I added a public string property named TitleLabel. I thought that the fact that it was a public property would be enough to allow setting it in the xaml designer and seeing what it would look like at design time. It didn't - at least, not quite. More on that later. First, I'll show you the UserControl.
When you only have one control, separating out the styles obviously isn't necessary. However, styles are one of the best features of WPF. That's why I've moved their definitions to a Resources section here, instead of setting these properties directly on the label. You would probably move these to the app.xaml file to make it easier to coordinate the styles of all of your controls.
The XAML for a UserControl named TitleLabel is shown below in Listing 1. The project, named UserControlLib, is of type WPF UserControl:
Path="FormTitle" refers to the public string property that I declared in the CodeBehind shown below in Listing 2. The Content attribute binding is a little odd, but this syntax is required when you bind to a public property, dependency or otherwise, inside a UserControl.
Note that since you need to pass the value of a property to the Content clause of the Label control inside the usercontrol, you need to add a "local" namespace at the top of the usercontrol in order to reference it. Up in the <Window tag, type
and a dialog will appear to let you choose the assembly that "local" will refer to in your xaml. Pick the name of the usercontrol project - "clr-namespace:UserControlLib" in this case.
Using a public property for the TitleLabel UserControl
The code-behind for the Usercontrol includes a public property called TitleLabel for the string that will appear as the form title. It's referred to in the "Path=" xaml, above:
When I drop my UserControl on a new WPF Window, I can open the Properties Window for the UserControl and set the FormTitle property to, say, Customers. But nothing happens. I have to Build the solution in order for the string "Customers" to appear on the form.
I suppose it's not a big deal, but I rather expected the title to be updated as I typed. I've seen such behavior elsewhere; what do I have to do to get the same thing for my UserControl?
Dependency Properties to the rescue
What I had to do was to comment out the public property TitleLabel and replace it with a Dependency Property of the same name. It's basically six lines of code. The name of your dependency property appears six times in these six lines, and three of those times the suffix "Property" is tacked onto the end of the propperty name. I've lined up the FormTitle references to make it easier to remember where "Property" has to be appended to your dependency property's name:
Now, as I enter the FormTitle property value directly into the window's xaml, it's instantly updated on the design surface. The FormTitle property also appears in the Property Window, although it doesn't update the title on the form until you move out of the value cell (Fig. 1).
In case this is all new to you, the solution with two projects in it is shown in Fig. 2, below. The code is available free in the download for this article. You just need to register (see the top of this article.) Create the UserControl project first, then the WPF project. When you open MainWindow.xaml and then open the ToolBox (Ctrl_Alt_X), if you've compiled your solution (F6), you'll see your usercontrol at the top of the ToolBox. Just drag it and drop it at the top of MainWindow.
There are other uses for dependency properties, but their implementation is always those six lines of code. (be sure to replace string with int or other type as needed). And I hope that they're implemented in a simpler way in the next generation of the .NET languages. The implementaton shouldn't be so arcane. But at least you now have a simple pattern to walk you throught the process.
So the next time you want instant gratification while working with your Usercontrols in the WPF Designer, use a Dependency Property instead of a plain public property, and you'll be glad you did.
See 'ya :)
|Copyright(C) Pinter Consulting, 2018||Tel: +1 (650) 464-6924|