绑定到静态属性


168

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

这是带有static属性的类:

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”的对象。标记文件'BurnDisk; component / selectversionpagefunction.xaml'中的对象'System.Windows.Data.Binding'出错,行57位置29。

知道我在做什么错吗?

Answers:


168

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

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

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

这个答案更适合我的情况,因为我不想在我的源类中引入DependencyObject。谢谢你的提示!
Anthony Brien

6
请注意,这将使您的文本框将值推回static属性,但在源值更改时不会更新文本框。
亚当·西尔斯

1
很好,在这种情况下,我只需要从文本框到源的绑定即可。如果我希望绑定以其他方式起作用,那么我知道需要以下一种方法:INotifyPropertyChanged,<PropertyName> Changed事件或依赖项属性。
Anthony Brien

1
注意:此解决方案在MVVM情况下不起作用,因为您通常无法访问要绑定到的对象的类型。
安东尼·伍兹

@thomas我很想让它为我工作,但不能。我在这里将我的困境发布为另一个问题:stackoverflow.com/questions/34656670/…–
安德鲁·辛普森

107

您不能像这样绑定到静态对象。由于没有涉及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}"/>

5
真?我已经能够绑定到与我的示例非常相似的静态Int32.MaxValue:<TextBox Text = {Binding Source = {x:Static sys:Int32.MaxValue},Mode = OneWay}“ />是工作是因为这是一种方法吗?
Anthony Brien

2
是的,任何两种方式的绑定都需要在绑定上使用Path属性值。Source必须是一个包含Path指定的属性的对象。指定OneWay将消除该限制。
亚当·希尔斯,2009年

另外,对于最新更新,我们深表歉意,但是我用示例更新了以上答案。
亚当·希尔斯,2009年

有没有办法绑定静态字符串。我有一个mutibinding,输入之一是固定的字符串。
Nitin Chaudhari,2010年

39

在.NET 4.5中,可以绑定到静态属性,更多内容

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

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

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


如果有人想阅读更多,这里是链接。微软记下了它,但它在此处的Web存档中。 web.archive.org/web/20131129053934/http://msdn.microsoft.com/...
C. Tewalt

这个答案为我指明了正确的方向,但是在没有示例的情况下仍然花了一些时间来制定细节。我已经根据原始代码编写了一个示例
马特

13

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

1
VersionManager级可以是静态的,一切仍然有效。注意路径定义中的花括号Path=(local:VersionManager.FilterString)。有谁知道为什么实际需要它们?
chviLadislav

2
路径定义中的括号是必需的,因为该属性是静态的,请参见此处
chviLadislav

11

绑定static属性可能有两种方法/语法。如果pstaticclass中的一个属性MainWindow,则bindingfor textbox将是:

1。

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

2。

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

9

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

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

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

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

8

如果您正在使用本地资源,则可以参考以下内容:

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

3

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。
Mark A. Donohoe

尝试了许多不同的解决方案,并且这个解决方案有效。PropertyChangedEventHandler对我有用。干杯。
Mgamerz

2

看一下我的项目CalcBinding,它为您提供了用Path属性值编写复杂表达式的方法,包括静态属性,源属性,Math等。因此,您可以这样编写:

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

祝好运!


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>

看起来像这样:

在此处输入图片说明

在MainWindow XAML的源代码中,您可能会遇到类似这样的事情,我们所做的一切都是通过textBlock.Texts get/ set功能直接更改值:

using System.Windows;

namespace MyWPFApp
{
    public partial class MainWindow : Window
    {
        public MainWindow() { InitializeComponent(); }

        private void Button_Click_Poke_Kilroy(object sender, RoutedEventArgs e)
        {
            textBlock.Text = "              \\|||/\r\n" +
                             "              (o o) \r\n" +
                             "----ooO- (_) -Ooo----";
        }
    }
}

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

在此处输入图片说明


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

-1

最佳答案(.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)}"/>

不要忽略括号

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.