Использование INotifyPropertyChanged в WPF

#c# #wpf #binding #inotifypropertychanged

#c# #wpf #привязка #inotifypropertychanged

Вопрос:

Привет, я пытаюсь использовать NotifyPropertyChanged для обновления всех мест, где я привязываю свойство. То, что я искал в INotifyPropertyChanged, указано в этих случаях.

Итак, мне нужна помощь, потому что я не понимаю, что у меня здесь не так. И я действительно не знаю, что делать с событием PropertyChange. Мой вопрос по этому поводу в том, когда он меняется? Что я должен еще с ним делать?

Datagrid:

 <ListView Name="listView" ItemsSource="{Binding Categories}"/>
  

Пример, когда я изменяю свое свойство Categories:

 DataTest dtTest = new DataTest();

public MainWindow()
{
    InitializeComponent();
    this.DataContext = dtTest;
}

private void Button1_Click(object sender, RoutedEventArgs e)
{
    //Here i pick up a string from a textBox, where i will insert in a Table of my DB,
    //Then i will do a query to my Table, and i will get a DataTable for example
    //Then i just put the contents into the DataView, so the value have changed.
    dtTest.Categories = dtTable.DefaultView;
    dtTest = dtTable.defaultView; (this only an example, i don't this for real.)
    //What i have to do now, to wherever i am binding (DataGrid, ListView, ComboBox)
    //the property to the new values automatically being showed in all places?
}
  

Мой класс:

 public class DataTest : INotifyPropertyChanged
{
    private DataView categories;

    public event PropertyChangedEventHandler PropertyChanged; //What i have to do with this?

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

    public DataView Categories
    {
        get { return categories; }
        set 
        {
            if (value != categories)
            {
                categorias = value;
                NotifyPropertyChanged("Categories");
            }
        }
    }
}
  

Мой класс с INotifyCollectionИзменен:

 public class DataTest : INotifyCollectionChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    private void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, e);
        }
    }

    public DataView Categories
    {
        get { return categories; }
        set 
        {
            if (value != categories)
            {
                categories = value;
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, Categories));
            }
        }
    }
}
  

Но почему PropertyChanged всегда равен NULL??? Я должен сделать что-то еще, но я не знаю, что.

Заранее спасибо!

Ответ №1:

DataTest класс должен быть DataContext для привязки. Вы можете установить это в code-behind (или множеством других способов, но для простоты — просто сделайте это в code-behind)

 public MainWindow() // constructor
{
    this.DataContext = new DataTest();
}
  

Затем, используя ‘Source’ набора привязок, вы можете указать ‘Path’, чтобы ваш xaml выглядел следующим образом:

 <ListBox ItemsSource="{Binding Categories}" />
  

Теперь, если свойство ‘Categories’ изменено в коде, NotifyPropertyChanged написанный вами код предупредит привязку, которая, в свою очередь, получит доступ к общедоступному получателю для свойства и обновит представление.

Комментарии:

1. И мне не нужно ничего делать с событием? Не обязательно инициализироваться? Или он теряет нулевое значение, когда свойства начали где-либо привязываться?

2. @Miguel Попробуйте — главное, установите DataContext для объекта, который вы привязываете, или, предпочтительно, родительский, например, Window. И тогда, да — привязка сделает всю работу за вас; вам не нужно создавать обработчик вручную!

3. Я попробовал то, что вы предложили, и как вы объяснили выше, и я поставил точку останова в NotifyPropertyChanged, чтобы проверить, является ли PropertyChanged нулевым или нет, но оно остается нулевым.

4. ХОРОШО — пара вещей. 1. Убедитесь, что поле backing написано правильно, у вас оно указано как ‘categories’ и ‘categorias’ в разных местах вашего примера кода (но, возможно, это просто опечатка в этом вопросе?) и 2. Установите точку останова в параметре установки свойств, потому что к моменту запуска этого кода (после нажатия кнопки) привязка будет настроена, и событие PropertyChanged будет ненулевым. Возможно, вы нарушали слишком рано, до того, как была настроена привязка.

5. Событие всегда равно нулю. Когда я изменил значения свойства, событие просто запустилось и всегда имеет значение null. Вы уверены, что мне не нужно инициализировать мой PropertyChangedEventHandler?

Ответ №2:

Получение обработчика предотвращает переход обработчика событий в null после проверки на null, а проверка на null предотвратит получение исключения null, если нет обработчиков событий.

Причина, по которой ваше значение PropertyChanged равно null, заключается в том, что к нему не привязаны обработчики событий. Причина, по которой к нему не привязаны обработчики, заключается в том, что вы ни к чему не привязали свой объект (что позаботится о добавлении обработчика) или вы не добавили к нему обработчик (если вы хотели наблюдать за ним по какой-либо другой причине). Как только ваш объект создан, вам нужно его куда-нибудь привязать.

Комментарии:

1. Итак, в этом случае, что я должен делать?

2. Что вы хотите, чтобы происходило в вашем элементе управления? В большинстве случаев вы не создаете привязку после нажатия кнопки, а вместо этого создаете привязку в XAML. Если у вас есть ListBox и вы хотите привязать к нему категории, вы должны сделать <ListBox ItemsSource={Привязка категорий} /> предполагая, что ваш DataContext установлен в качестве объекта DataTest, который вы хотите заполнить ItemsSource. Скорее всего, вам нужен какой-то способ предоставить текущий тест данных в XAML (возможно, свойство DependencyProperty) и привязать на основе этого свойства.

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

Ответ №3:

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

Комментарии:

1. Хорошо, итак, мой случай следующий… Я обновляю это представление данных, например, выполняю запрос и помещаю данные в DataView, и значение свойства изменилось, но событие PorpertyChanged всегда равно null!! Почему? Я должен сделать что-то еще с PropertyChanged, но я не могу понять, что и где… Это моя проблема. Представьте, что я нажал на кнопку, а затем изменил значение этого свойства, что мне нужно делать дальше?

2. Если PropertyChanged равно null, это означает, что нет клиентов, прослушивающих событие. Почему это было бы трудно сказать без дополнительной информации.

3. Это как-то связано с привязками? Я привязываю свойство более чем в одном месте, поэтому я не думаю, что это связано с привязками. Я должен сделать что-то еще, но не могу понять, что… Должен ли я сделать что-то вроде этого «dtTest.PropertyChanged = ?» ???

4. Отредактируйте свой вопрос с помощью небольшого примера, демонстрирующего вашу проблему.

5. Я отредактировал свое событие Button_Click, чтобы дать лучшее объяснение. Итак, я думаю, что я должен прикрепить некоторый обработчик к моему PropertyChanged или сделать что-то с ним в моем окне, чтобы он не был NULL, верно? Но что?