Mark A. Donohoe
Mark A. Donohoe

Reputation: 30458

How do you set up a binding to a static property from code-behind? (WPF 4.5+)

In XAML, setting up a binding to a static property is simple...

<TextBlock Text="{Binding Path=(foo:StaticClass.StaticProperty)}" />

How do you achieve the same thing in code?

I've tried the following:

var b = new Binding(){
    Path = new PropertyPath(StaticClass.StaticProperty)
};

var b = new Binding(){
    Path = new PropertyPath("StaticClass.StaticProperty")
};

var b = new Binding(){
    Source = StaticClass,
    Path   = new PropertyPath("StaticProperty")
};

...but none of the above work.

This works to set the initial value, but doesn't update...

var binding = new Binding(){
    Source = StaticClass.StaticProperty
};

The only way I've managed to get it to work so far is like this...

public static Binding CreateStaticBinding(Type classType, string propertyName){

    var xaml = $@"
        <Binding
            xmlns    = ""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
            xmlns:is = ""clr-namespace:{$"{classType.Namespace};assembly={classType.Assembly.GetName().Name}"}""
            Path=""(is:{classType.Name}.{propertyName})"" />";

    return (Binding)System.Windows.Markup.XamlReader.Parse(xaml);
}

...but MAN does that annoy me I have to resort to creating dynamic XAML, then parsing it! UGH!! But hey... it works.

I have to think there's an easier way! So what is it?

Upvotes: 1

Views: 730

Answers (2)

ASh
ASh

Reputation: 35720

I needed to go deeper with this problem and bind to nested property of a static property which has non-privitive type: Thread.CurrentThread.CurrentCulture.NativeName (Thread.CurrentThread is a static property of Thread class, CurrentCulture is an instance property of Thread class, NativeName is an instance property of CultureInfo class).

in XAML binding path is set as:

<Window xmlns:threading="clr-namespace:System.Threading;assembly=mscorlib">
...
<TextBlock 
     Name="txtCulture" 
     Text="{Binding Path=(threading:Thread.CurrentThread).CurrentCulture.NativeName}" />

so in code I had to use PropertyPath constructor with path and parameters and write it like this (using the approach which also works with DependencyProperties):

System.Reflection.PropertyInfo staticProperty = 
    typeof(Thread).GetProperty(nameof(Thread.CurrentThread));

var cultureBinding = new Binding
{
    Path = new PropertyPath("(0).CurrentCulture.NativeName", staticProperty)
};

txtCulture.SetBinding(TextBlock.TextProperty, cultureBinding);

Upvotes: 1

Alex.Wei
Alex.Wei

Reputation: 1883

Create a PropertyPath by xaml paserer is different from constructor of Binding. So you should use code in below to get it work.

var binding = new Binding() {
    Path = new PropertyPath(typeof(StaticClass).GetProperty(nameof(StaticClass.StaticProperty))),
};

Upvotes: 2

Related Questions