绑定到静态属性

Posted

技术标签:

【中文标题】绑定到静态属性【英文标题】:Binding to static property 【发布时间】:2010-10-30 11:52:38 【问题描述】:

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

这是具有静态属性的类:

public class VersionManager

    private static string filterString;

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

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

<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 行。

知道我做错了什么吗?

【问题讨论】:

【参考方案1】:

你不能绑定到这样的静态。由于不涉及 DependencyObject(或实现 INotifyPropertyChanged 的对象实例),因此绑定基础架构无法收到更新通知。

如果该值没有改变,只需放弃绑定并直接在Text 属性内使用x:Static。将下面的 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"/>

【讨论】:

真的吗?我已经能够绑定到与我的示例非常相似的静态 Int32.MaxValue: 就是这样因为这是一种方式而工作? 是的,任何双向绑定都需要绑定上的 Path 属性值。 Source 需要是一个包含 Path 指定的属性的对象。指定 OneWay 会消除该限制。 另外,很抱歉更新较晚,但我用示例更新了上述答案。 有没有办法绑定静态字符串。我有一个多重绑定,其中一个输入是固定字符串。【参考方案2】:

如果需要双向绑定,则必须提供路径。

如果类不是静态的,则对静态属性进行双向绑定有一个技巧:在资源中声明该类的虚拟实例,并将其用作绑定源。

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

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

【讨论】:

这个答案更适合我的情况,因为我不想将 DependencyObject 引入我的源类。感谢您的提示! 请注意,这将使您的文本框能够将值推回静态属性,但不会在源值更改时更新文本框。 没关系,在这种情况下,我只需要从文本框到源的绑定。如果我希望绑定以另一种方式工作,我知道需要以下方法之一:INotifyPropertyChanged、Changed 事件或依赖属性。 注意:此解决方案不适用于 MVVM 情况,因为您通常无权访问要绑定的对象的类型。 @thomas 我很想让它为我工作,但不能。我在这里发布了我的困境作为另一个问题:***.com/questions/34656670/…【参考方案3】:

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

您可以使用静态属性作为数据绑定的来源。这 数据绑定引擎识别属性值何时更改,如果 引发静态事件。例如,如果类 SomeClass 定义了一个 静态属性叫做 MyProperty,SomeClass 可以定义一个静态事件 当 MyProperty 的值更改时引发。静态事件 可以使用以下任一签名:

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

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

【讨论】:

这里是链接,以防有人想阅读更多内容。微软将其删除,但它在此处的网络存档中。 web.archive.org/web/20131129053934/http://msdn.microsoft.com/… 这个答案为我指明了正确的方向,但是在没有示例的情况下仍然需要一段时间才能弄清楚细节。我根据原代码写了一个example。【参考方案4】:

您可以使用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】:

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

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

【讨论】:

【参考方案6】:

可能有两种方法/语法来绑定static 属性。如果 p 是类 MainWindow 中的 static 属性,则 textboxbinding 将是:

1.

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

2.

<TextBox Text="Binding Source=x:Static local:MainWindow.p,Mode=OneTime" />

【讨论】:

【参考方案7】:

看看我的项目CalcBinding,它提供给你写复杂的Path属性值表达式,包括静态属性、源属性、Math等。所以,你可以这样写:

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

祝你好运!

【讨论】:

【参考方案8】:

从 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)"/>

【讨论】:

VersionManager 类可以是静态的,并且一切正常。注意路径定义中的大括号Path=(local:VersionManager.FilterString)。有谁知道为什么需要它们? 路径定义中需要大括号,因为属性是静态的,见here @Matt 我怎么知道我的 wpf 版本? 另请注意,与“普通”绑定不同,您不能在此处省略 Path=【参考方案9】:

.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)" />

【讨论】:

对您的代码稍作更改以正确调用 EventHandler。 尝试了很多不同的解决方案,这个成功了。 PropertyChangedEventHandler 对我有用。干杯。【参考方案10】:

最简单的答案(.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)"/>

不要忽略括号

【讨论】:

【参考方案11】:

另一种解决方案是创建一个像这样实现 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));
    

【讨论】:

以上是关于绑定到静态属性的主要内容,如果未能解决你的问题,请参考以下文章

绑定到 WPF 中静态类中的静态属性

WPF 绑定到静态属性(4.5)

数据绑定—Source(绑定到静态类的静态属性)

如何创建静态可绑定属性描述对象

将静态方法/函数绑定到 XAML 中的 Func<T> 属性

WPF:将静态资源绑定到用户控件中的依赖项属性