Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

WPF 4.5: Binding and change notification for static properties

Pete Brown - 29 November 2011

One of the new features in WPF 4.5 is support for binding to static properties. In addition to the binding syntax itself, there's new support for static property change notification.

In many cases, it is still advisable to use a Singleton pattern or another approach for binding. However, there are cases when your application design requires binding to static properties. In those cases, WPF should kindly step out of the way and let you accomplish your task the way you've architected it.

Two Approaches to Change Notification

There are two ways to notify the binding system of property changes, both of which follow the same pattern as their instance-based relatives.

The first is to create a static event named <propertyName>Changed. Raise this event when the property changes. Here's an example:

public static class AppSettings
{
public static event EventHandler StorageFolderChanged;

private static string _storageFolder;
public static string StorageFolder
{
get { return _storageFolder; }
set
{
if (value != _storageFolder)
{
_storageFolder = value;

if (StorageFolderChanged != null)
StorageFolderChanged(null, EventArgs.Empty);
}
}
}
}

The static property name in this example is StorageFolder. The event name is therefore StorageFolderChanged. Note that nothing useful is passed as part of the event - there's no instance to provide and no event args.

The second approach is to create a single event which is the static version of the INPC PropertyChanged event named StaticPropertyChanged. This requires using the System.ComponentModel namespace to pull in the PropertyChangedEventArgs definition.

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;

private static int _speedFactor;
public static int SpeedFactor
{
get { return _speedFactor; }
set
{
if (value != _speedFactor)
{
_speedFactor = value;

NotifyStaticPropertyChanged("SpeedFactor");
}
}
}

private static void NotifyStaticPropertyChanged(string propertyName)
{
if (StaticPropertyChanged != null)
StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}

For this, I followed the same pattern I do with instance classes, pulling the change notification out into a separate function.

Code-Behind

I have the tiniest bit of code-behind here, just to set the initial values.

public MainWindow()
{
InitializeComponent();

AppSettings.SpeedFactor = 10;
AppSettings.StorageFolder = @"d:\Foo\Bar";
}

Binding

Here's the XAML UI for this sample app. There are two TextBlock elements bound to properties of the AppSettings class. In addition, there's a single TextBox bound to one of the same properties using ToWay binding.

<Window x:Class="Wpf45StaticBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf45StaticBinding"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize"
Value="35" />
</Style>
<Style TargetType="TextBox">
<Setter Property="FontSize"
Value="35" />
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox x:Name="StorageFolderField"
Text="{Binding Path=(local:AppSettings.StorageFolder), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock x:Name="StorageFolderDisplay"
Text="{Binding Path=(local:AppSettings.StorageFolder)}" />
<TextBlock x:Name="SpeedFactorDisplay"
Text="{Binding Path=(local:AppSettings.SpeedFactor)}" />

</StackPanel>
</Grid>
</Window>

Note the modification to the binding syntax. You'll use parentheses around the namespace, class, and property because, as Sam Bent explained to me "They tell us to parse the path as ClassName.PropertyName rather than PropertyName.PropertyName."

image

Oh, and Ignore those. Umm, and ignore this too.

image

As is sometimes the case during preview builds, the IDE/parser and the code base are not quite in sync. In this case, it doesn't recognize the cool new static binding syntax and is trying to parse it as an attached property. Never fear! This example still works :)

Go ahead and run it. Change the value in the TextBox. You should see the value in the TextBlock update, just as you would with normal instance binding.

imageimage

You can also add in another TextBox to test out the numeric field and its own change notification.

Binding to static properties fills a need many of our customers have, and it's one more way that WPF gets out of the way of the solution you're trying to implement. It just works.

       

Source Code and Related Media

Download /media/81044/wpf45staticbinding.zip
posted by Pete Brown on Tuesday, November 29, 2011
filed under:        

8 comments for “WPF 4.5: Binding and change notification for static properties”

  1. Mario Vernarisays:
    Hello Pete.
    This new feature is interesting, but...what's the goal?
    I'd be scared about binding an instance to a static source via regular (i.e. not weak) event: this is one of the primary causes of memory-leak.
    Has to be intended as a weak-event usage shortcut, instead?
    Thanks.
    Cheers
  2. Petesays:
    @Mario

    I personally prefer to use a singleton if anything. It's more intuitive and provides better control over lifetime. Of course, you can also inject something in and handle it that way. However, customers (who understand what this means) have asked for this specific feature.

    I'd have to see what the binding system does when the page goes away. There honestly should be no more *real* risk there than binding to an instance.

    Pete
  3. Paulussays:
    Hi Pete,

    1.- "They tell us to parse the path as ClassName.PropertyName rather than PropertyName.PropertyName." and, probably more importantly, to ignore the DataContext.

    This is the reason why I am also scared about memory-leaks in this solution since there is no DataContext switching/nullifying to tell the binding system to unhook {... Path=...} events in an automated way.

    2.- Barring any error on my part, would a valid singleton solution using this syntax be:

    (local:AppSettings.Singleton.StorageFolder) where 'Singleton' is a static property that refers to an instance of AppSettings and StorageFolder be an instance property instead of a static property. I have indeed doubts that this actually works since now we are kind of mixing instance path logic inside class path logic.

    Kind regards, Paulus
  4. Petesays:
    @Shubhan

    To the best of my knowledge, this does not work with Metro style apps or Silverlight.

    @Paulus

    Quite honestly, I'm not a fan of this approach. It's provided because customers really wanted it, but I really do think it's potentially dangerous to use in many cases. During my WPF 4.5 talks, I warn people of the pitfalls of this approach.

    On #2 I'd set the datacontext from code behind or something. No, the syntax you offered will not work because the property is not static. This approach is for static properties only.

    Pete
  5. Petesays:
    @Mario

    Following back up. Yes, this has risks. Reading my answer to you, I didn't make a big enough point about the feature being targeted towards customers who requested it to get through specific situations.

    Yes, there's danger with stuff sticking around. In theory, this is no worse than regular binding, but in practice, it is far easier to have pages stuck in memory because they are tied to the long-lived static object.

    Pete

Comment on this Post

Remember me