Binding to static property

2018-12-31 14:32发布

I'm having a hard time binding a simple static string property to a text box.

Here's the class with the static property:

public class VersionManager
{
    private static string filterString;

    public static string FilterString
    {
        get { return filterString; }
        set { filterString = value; }
    }
}

In my xaml, I just want to bind this static property to a text box:

<TextBox>
    <TextBox.Text>
        <Binding Source="{x:Static local:VersionManager.FilterString}"/>
    </TextBox.Text>
</TextBox>

Everything compiles, but at run time, I get the following exception:

Cannot convert the value in attribute 'Source' to object of type 'System.Windows.Markup.StaticExtension'. Error at object 'System.Windows.Data.Binding' in markup file 'BurnDisk;component/selectversionpagefunction.xaml' Line 57 Position 29.

Any idea what I'm doing wrong?

9条回答
十年一品温如言
2楼-- · 2018-12-31 14:44

Right variant for .NET 4.5 +

C# code

public class VersionManager
{
    private static string filterString;

    public static string FilterString
    {
        get => filterString;
        set
        {
            if (filterString == value)
                return;

            filterString = value;

            StaticPropertyChanged?.Invoke(null, FilterStringPropertyEventArgs);
        }
    }

    private static readonly PropertyChangedEventArgs FilterStringPropertyEventArgs = new PropertyChangedEventArgs (nameof(FilterString));
    public static event PropertyChangedEventHandler StaticPropertyChanged;
}

XAML binding (attention to braces they are (), not {})

<TextBox Text="{Binding Path=(yournamespace:VersionManager.FilterString)}" />
查看更多
只靠听说
3楼-- · 2018-12-31 14:45

In .NET 4.5 it's possible to bind to static properties, read more

You can use static properties as the source of a data binding. The data binding engine recognizes when the property's value changes if a static event is raised. For example, if the class SomeClass defines a static property called MyProperty, SomeClass can define a static event that is raised when the value of MyProperty changes. The static event can use either of the following signatures:

public static event EventHandler MyPropertyChanged; 
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged; 

Note that in the first case, the class exposes a static event named PropertyNameChanged that passes EventArgs to the event handler. In the second case, the class exposes a static event named StaticPropertyChanged that passes PropertyChangedEventArgs to the event handler. A class that implements the static property can choose to raise property-change notifications using either method.

查看更多
路过你的时光
4楼-- · 2018-12-31 14:45

If you are using local resources you can refer to them as below:

<TextBlock Text="{Binding Source={x:Static prop:Resources.PerUnitOfMeasure}}" TextWrapping="Wrap" TextAlignment="Center"/>
查看更多
浮光初槿花落
5楼-- · 2018-12-31 14:47

As of WPF 4.5 you can bind directly to static properties and have the binding automatically update when your property is changed. You do need to manually wire up a change event to trigger the binding updates.

public class VersionManager
{
    private static String _filterString;        

    /// <summary>
    /// A static property which you'd like to bind to
    /// </summary>
    public static String FilterString
    {
        get
        {
            return _filterString;
        }

        set
        {
            _filterString = value;

            // Raise a change event
            OnFilterStringChanged(EventArgs.Empty);
        }
    }

    // Declare a static event representing changes to your static property
    public static event EventHandler FilterStringChanged;

    // Raise the change event through this static method
    protected static void OnFilterStringChanged(EventArgs e)
    {
        EventHandler handler = FilterStringChanged;

        if (handler != null)
        {
            handler(null, e);
        }
    }

    static VersionManager()
    {
        // Set up an empty event handler
        FilterStringChanged += (sender, e) => { return; };
    }

}

You can now bind your static property just like any other:

<TextBox Text="{Binding Path=(local:VersionManager.FilterString)}"/>
查看更多
十年一品温如言
6楼-- · 2018-12-31 14:57

You can use ObjectDataProvider class and it's MethodName property. It can look like this:

<Window.Resources>
   <ObjectDataProvider x:Key="versionManager" ObjectType="{x:Type VersionManager}" MethodName="get_FilterString"></ObjectDataProvider>
</Window.Resources>

Declared object data provider can be used like this:

<TextBox Text="{Binding Source={StaticResource versionManager}}" />
查看更多
泪湿衣
7楼-- · 2018-12-31 14:58

You can't bind to a static like that. There's no way for the binding infrastructure to get notified of updates since there's no DependencyObject (or object instance that implement INotifyPropertyChanged) involved.

If that value doesn't change, just ditch the binding and use x:Static directly inside the Text property. Define app below to be the namespace (and assembly) location of the VersionManager class.

<TextBox Text="{x:Static app:VersionManager.FilterString}" />

If the value does change, I'd suggest creating a singleton to contain the value and bind to that.

An example of the singleton:

public class VersionManager : DependencyObject {
    public static readonly DependencyProperty FilterStringProperty =
        DependencyProperty.Register( "FilterString", typeof( string ),
        typeof( VersionManager ), new UIPropertyMetadata( "no version!" ) );
    public string FilterString {
        get { return (string) GetValue( FilterStringProperty ); }
        set { SetValue( FilterStringProperty, value ); }
    }

    public static VersionManager Instance { get; private set; }

    static VersionManager() {
        Instance = new VersionManager();
    }
}
<TextBox Text="{Binding Source={x:Static local:VersionManager.Instance},
                        Path=FilterString}"/>
查看更多
登录 后发表回答