Простое связывание данных .NET не работает - PullRequest
2 голосов
/ 23 февраля 2012

Технология: .NET 4, C #, WinForms, Visual Studio 2010

Я нахожусь в обработке привязки обучающих данных и не смог получить даже простой пример для работы, как ожидалось. У меня есть форма с меткой, к которой я привязываю, которая показывает текущие координаты курсора мыши.

public partial class Form1 : Form, INotifyPropertyChanged
{
    [Bindable(true)]
    private String cursorPosition;
    public String CursorPosition
    {
        get
        {
            return cursorPosition;
        }

        set
        {
            cursorPosition = value;
            NotifyPropertyChanged("CursorPosition");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        CursorPosition = "(" + Convert.ToString(e.X) + " , " + Convert.ToString(e.Y) + ")";
    }

    private void NotifyPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 
}

От дизайнера я установил привязку данных метки, чтобы привязать свойство Text к form1BindingSource - CursorPosition. Чего мне не хватает?

Редактировать: Обновлен фрагмент кода.

Ответы [ 4 ]

6 голосов
/ 23 февраля 2012

От дизайнера я установил привязку данных метки, чтобы привязать свойство Text к form1BindingSource - CursorPosition. Чего мне не хватает?

Вы установили:

form1BindingSource.DataSource = this;  // (or whatever the real data source is)

например. в конструкторе формы, после InitializeComponent?

(Предполагается, что ваш экземпляр Form1 является источником данных, и вы привязываете к нему элементы управления через BindingSource.)


Несколько дополнительных подробных предложений:

  1. Выбор самой формы в качестве источника данных несколько необычен. ИМХО, лучше разделить все связанные свойства в отдельный объект данных, не относящийся к пользовательскому интерфейсу. Это позволит вам создать повторно используемый базовый тип для реализации INotifyPropertyChanged.

  2. Как говорит @rfmodulator в своем ответе, BindableAttribute присоединено к полю:

    [Bindable(true)]
    private String cursorPosition;
    public String CursorPosition
    …
    

    Вы, вероятно, хотели прикрепить его к свойству:

    private String cursorPosition;
    [Bindable(true)]
    public String CursorPosition
    …
    
  3. Ваш сеттер , вероятно, должен выглядеть следующим образом:

    set
    {
        if (!string.Equals(cursorPosition, value)      // +
        {                                              // +
            cursorPosition = value;
            NotifyPropertyChanged("CursorPosition");
        }                                              // +
    }
    

    То есть, событие PropertyChanged вызывается только тогда, когда значение свойства действительно изменяется.

  4. Возможно, вы захотите изменить NotifyPropertyChanged метод на этот:

    private void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;          // +
        if (handler != null)                                            // ~
        {
            handler(this, new PropertyChangedEventArgs(propertyName));  // ~
        }
    }
    

    Это потому, что PropertyChanged может в теории измениться между проверкой null и вызовом. Вы можете исключить эту теоретическую возможность, создав локальную копию делегата события.

    PS: Если быть точным, как указывает Джеффри Рихтер в своей книге "CLR via C #", локальной переменной все еще недостаточно: в идеале вы должны присвоить Interlocked.CompareExchange(ref PropertyChanged, null, null) для handler (вместо этого просто PropertyChanged), поскольку использование этого метода не позволит генератору кода JIT оптимизировать локальную переменную (IIRC).

2 голосов
/ 23 февраля 2012

Полагаю, вы хотите, чтобы событие PropertyChanged сработало?Вы устанавливаете значение вспомогательной переменной в Mouse_Move, а не значение свойства.В результате вызов NotifyPropertyChanged не будет вызван.

1 голос
/ 23 февраля 2012

Вы устанавливаете атрибут Bindable в поле, но вызываете NotifyPropertyChanged со свойством в качестве аргумента.

1 голос
/ 23 февраля 2012

Не следует реализовывать INotifyPropertyChanged для компонентов , , элементов управления и форм , поскольку привязка данных будет опираться на парадигму события XXXChanged для прослушивания уведомлений об изменениях. Внутри привязки данных используются дескрипторы свойств для прослушивания событий изменения. Они намекают, как класс обнаруживает изменения в документации для свойства PropertyDescriptor.SupportsChangeEvents . Это связано с историей привязки данных winforms. XXXChanged был способом связывания данных и уведомления об изменениях до .NET 2.0. INotifyPropertyChanged был представлен в 2.0 в пользу шаблона XXXChanged.

Свойство SupportsChangeEvents указывает, могут ли уведомления об изменении значения для этого свойства поступать извне дескриптора свойства, например, из самого компонента, или же уведомления будут исходить только от прямых вызовов метода SetValue. Например, компонент может реализовывать интерфейс INotifyPropertyChanged или может иметь явное событие nameChanged для этого свойства.

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