绑定到静态属性

时间:2009-06-01 19:20:49

标签: wpf xaml data-binding

我很难将简单的静态字符串属性绑定到文本框。

这是具有静态属性的类:

public class VersionManager
{
    private static string filterString;

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

在我的xaml中,我只想将此静态属性绑定到文本框:

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

所有内容都会编译,但在运行时,我会遇到以下异常:

  

无法转换属性中的值   '源'到类型的对象   'System.Windows.Markup.StaticExtension'。   对象出错   'System.Windows.Data.Binding'中   标记文件   'BurnDisk;组件/ selectversionpagefunction.xaml'   第57行第29位。

知道我做错了吗?

12 个答案:

答案 0 :(得分:157)

如果绑定需要双向,则必须提供路径。如果类不是静态的,那么对静态属性进行双向绑定有一个技巧:在资源中声明类的虚拟实例,并将其用作绑定的源。

<Window.Resources>
    <local:VersionManager x:Key="versionManager"/>
</Window.Resources>
...

<TextBox Text="{Binding Source={StaticResource versionManager}, Path=FilterString}"/>

答案 1 :(得分:98)

你无法绑定到那样的静态。绑定基础结构无法获得更新通知,因为没有涉及DependencyObject(或实现INotifyPropertyChanged的对象实例)。

如果该值没有改变,只需抛弃绑定并直接在x:Static属性中使用Text。将下面的app定义为VersionManager类的名称空间(和程序集)位置。

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

如果值确实发生了变化,我建议创建一个单例以包含该值并绑定到该值。

单身人士的一个例子:

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}"/>

答案 2 :(得分:38)

在.NET 4.5中,可以绑定到静态属性read more

  

您可以使用静态属性作为数据绑定的来源。该   如果a,则数据绑定引擎会识别属性值的变化   引发静态事件。例如,如果SomeClass类定义了一个   名为MyProperty的静态属性,SomeClass可以定义一个静态事件   当MyProperty的值发生变化时引发。静态事件   可以使用以下任一签名:

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

请注意,在第一种情况下,该类公开名为的静态事件   将EventArgs传递给事件处理程序的PropertyNameChanged。   在第二种情况下,该类公开名为的静态事件   将PropertyChangedEventArgs传递给的StaticPropertyChanged   事件处理程序实现静态属性的类可以选择   使用任一方法提出财产变更通知。

答案 3 :(得分:10)

从WPF 4.5开始,您可以直接绑定到静态属性,并在更改属性时自动更新绑定。您需要手动连接更改事件以触发绑定更新。

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; };
    }

}

您现在可以像其他任何一样绑定您的静态属性:

<TextBox Text="{Binding Path=(local:VersionManager.FilterString)}"/>

答案 4 :(得分:8)

您可以使用ObjectDataProvider类及其MethodName属性。它看起来像这样:

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

声明的对象数据提供者可以像这样使用:

<TextBox Text="{Binding Source={StaticResource versionManager}}" />

答案 5 :(得分:7)

如果您使用的是本地资源,可以按以下方式参考:

<TextBlock Text="{Binding Source={x:Static prop:Resources.PerUnitOfMeasure}}" TextWrapping="Wrap" TextAlignment="Center"/>

答案 6 :(得分:6)

绑定static属性可能有两种方法/语法。如果 p static 类中的MainWindow属性,则binding的{​​{1}}将为:

<强> 1

textbox

<强> 2

<TextBox Text="{x:Static local:MainWindow.p}" />

答案 7 :(得分:2)

查看我的项目CalcBinding,它提供了在Path属性值中编写复杂表达式,包括静态属性,源属性,Math和其他。所以,你可以这样写:

<TextBox Text="{c:Binding local:VersionManager.FilterString}"/>

古德勒克!

答案 8 :(得分:2)

.NET 4.5的右变体+

C#代码

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绑定(注意括号是(),而不是{})

<TextBox Text="{Binding Path=(yournamespace:VersionManager.FilterString)}" />

答案 9 :(得分:0)

最佳答案(.net 4.5及更高版本):

    static public event EventHandler FilterStringChanged;
    static string _filterString;
    static public string FilterString
    {
        get { return _filterString; }
        set
        {
            _filterString= value;
            FilterStringChanged?.Invoke(null, EventArgs.Empty);
        }
    }

和XAML:

    <TextBox Text="{Binding Path=(local:VersionManager.FilterString)}"/>

不要忽略括号

答案 10 :(得分:0)

如果您想遵循良好的约定,那么这些答案都很好,但是OP想要简单的东西,这也是我想要的,而不是处理GUI设计模式。如果您只想在基本的GUI应用程序中包含一个字符串,就可以随意更新即席更新,您可以直接在C#源代码中直接访问它。

假设您有这样一个非常基本的WPF应用程序MainWindow XAML,

<Window x:Class="MyWPFApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:MyWPFApp"
            mc:Ignorable="d"
            Title="MainWindow"
            Height="200"
            Width="400"
            Background="White" >
    <Grid>
        <TextBlock x:Name="textBlock"                   
                       Text=".."
                       HorizontalAlignment="Center"
                       VerticalAlignment="Top"
                       FontWeight="Bold"
                       FontFamily="Helvetica"
                       FontSize="16"
                       Foreground="Blue" Margin="0,10,0,0"
             />
        <Button x:Name="Find_Kilroy"
                    Content="Poke Kilroy"
                    Click="Button_Click_Poke_Kilroy"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    FontFamily="Helvetica"
                    FontWeight="Bold"
                    FontSize="14"
                    Width="280"
            />
    </Grid>
</Window>

这看起来像这样:

enter image description here

在MainWindow XAML的源代码中,您可能会遇到类似这样的事情,我们所做的全部工作都是通过textBlock.Text的{​​{1}} / get功能直接更改值:

set

然后,当您通过单击按钮触发该单击事件时,瞧! Kilroy出现:)

enter image description here

答案 11 :(得分:0)

另一种解决方案是创建一个普通的类,该类实现了PropertyChanger这样的

public class ViewProps : PropertyChanger
{
    private string _MyValue = string.Empty;
    public string MyValue
    {
        get { 
            return _MyValue
        }
        set
        {
            if (_MyValue == value)
            {
                return;
            }
            SetProperty(ref _MyValue, value);
        }
    }
}

然后在您不会创建的地方创建该类的静态实例

public class MyClass
{
    private static ViewProps _ViewProps = null;
    public static ViewProps ViewProps
    {
        get
        {
            if (_ViewProps == null)
            {
                _ViewProps = new ViewProps();
            }
            return _ViewProps;
        }
    }
}

现在将其用作静态属性

<TextBlock  Text="{x:Bind local:MyClass.ViewProps.MyValue, Mode=OneWay}"  />

这是PropertyChanger的必要实现

public abstract class PropertyChanger : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value)) return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}