Привязка к статическому свойству - PullRequest
161 голосов
/ 01 июня 2009

Мне трудно связать свойство простой статической строки с текстовым полем.

Вот класс со статическим свойством:

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.

Есть идеи, что я делаю не так?

Ответы [ 11 ]

159 голосов
/ 02 июня 2009

Если привязка должна быть двусторонней, вы должны указать путь. Существует хитрость для двусторонней привязки статического свойства, при условии, что класс не является статическим: объявите фиктивный экземпляр класса в ресурсах и используйте его в качестве источника привязки.

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

<TextBox Text="{Binding Source={StaticResource versionManager}, Path=FilterString}"/>
98 голосов
/ 01 июня 2009

Вы не можете связать со статикой, как это. Инфраструктура привязки не может получать уведомления об обновлениях, поскольку в нее не вовлечен 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}"/>
38 голосов
/ 22 сентября 2011

В .NET 4.5 можно привязывать к статическим свойствам, читать дальше

Вы можете использовать статические свойства в качестве источника привязки данных. механизм привязки данных распознает, когда значение свойства изменяется, если статическое событие Например, если класс SomeClass определяет статическое свойство MyProperty, SomeClass может определять статическое событие это повышается, когда значение MyProperty изменяется. Статическое событие может использовать одну из следующих подписей:

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

Обратите внимание, что в первом случае класс предоставляет статическое событие с именем PropertyNameChanged, который передает EventArgs в обработчик событий. Во втором случае класс предоставляет статическое событие с именем StaticPropertyChanged, который передает PropertyChangedEventArgs в обработчик события. Класс, который реализует статическое свойство, может выбрать поднять уведомления об изменении свойства, используя любой из методов.

10 голосов
/ 22 ноября 2017

Начиная с 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)}"/>
8 голосов
/ 23 января 2013

Вы можете использовать ObjectDataProvider класс и его свойство MethodName. Это может выглядеть так:

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

Объявленный объект данных провайдера можно использовать так:

<TextBox Text="{Binding Source={StaticResource versionManager}}" />
7 голосов
/ 04 июля 2014

Если вы используете локальные ресурсы, вы можете обращаться к ним, как показано ниже:

<TextBlock Text="{Binding Source={x:Static prop:Resources.PerUnitOfMeasure}}" TextWrapping="Wrap" TextAlignment="Center"/>
6 голосов
/ 22 января 2016

Может быть два способа / синтаксиса для привязки свойства static. Если p является свойством static в классе MainWindow, то binding для textbox будет:

1.

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

2.

<TextBox Text="{Binding Source={x:Static local:MainWindow.p},Mode=OneTime}" />
3 голосов
/ 01 сентября 2018

Правильный вариант для .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)}" />
2 голосов
/ 13 ноября 2016

Посмотрите на мой проект CalcBinding , который предоставляет вам написание сложных выражений в значении свойства Path, включая статические свойства, свойства источника, Math и другие. Итак, вы можете написать это:

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

Гудлак!

0 голосов
/ 10 мая 2019

Все эти ответы хороши, если вы хотите следовать хорошим соглашениям, но ОП хотел что-то простое , что я и хотел вместо того, чтобы иметь дело с шаблонами проектирования GUI. Если все, что вам нужно сделать, это добавить строку в базовое приложение с графическим интерфейсом, вы можете обновить ad-hoc без каких-либо сложностей, вы можете просто получить к ней доступ непосредственно в исходном коде 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 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----";
        }
    }
}

Затем, когда вы запускаете это событие, нажав кнопку, вуаля! Появляется Килрой:)

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...