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

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

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

Сетка данных:

<ListView Name="listView" ItemsSource="{Binding 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");
            }
        }
    }
}

Мой класс с INotifyCollectionChanged:

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??? Я должен сделать что-то еще, но я не знаю, что.

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


person Miguel    schedule 26.04.2011    source источник


Ответы (3)


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

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

Затем с помощью «Источника» набора привязок вы можете указать «Путь», чтобы ваш xaml выглядел так:

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

Теперь, если свойство «Категории» изменено в коде, написанный вами код NotifyPropertyChanged предупредит Binding, который, в свою очередь, получит доступ к общедоступному получателю свойства и обновит представление.

person kiwipom    schedule 26.04.2011
comment
И мне ничего не нужно делать с событием? Не нужно инициализировать? Или он теряет значение Null, когда Свойства начали где-то привязываться? - person Miguel; 26.04.2011
comment
@Miguel Попробуйте - главное, установите DataContext для того, к чему вы привязываетесь, или, что предпочтительнее, для родителя, например для окна. И тогда да — Binding сделает всю работу за вас; вам не нужно создавать обработчик вручную! - person kiwipom; 26.04.2011
comment
Я попробовал то, что вы предложили, и как вы объяснили выше, и я поставил точку останова в NotifyPropertyChanged, чтобы проверить, является ли PropertyChanged нулевым или нет, но он остается нулевым. - person Miguel; 26.04.2011
comment
ОК - пара вещей. 1. Убедитесь, что вспомогательное поле написано правильно, оно у вас есть как «категории» и «категории» в разных местах вашего примера кода (но, может быть, это просто опечатка в этом вопросе?) и 2. Поставьте точку останова на установщик свойств, потому что к тому времени, когда этот код будет запущен (после того, как вы нажмете кнопку), привязка будет настроена, а событие PropertyChanged будет ненулевым. Возможно, вы сломались слишком рано, до того, как была установлена ​​привязка. - person kiwipom; 26.04.2011
comment
Событие всегда равно нулю. Когда я изменил значения свойства, событие просто запустилось и всегда всегда равно нулю. Вы уверены, что мне не нужно инициализировать обработчик PropertyChangedEventhandler? - person Miguel; 26.04.2011
comment
@Miguel: Можете ли вы показать свой измененный код? И да, в обработчике событий нечего инициализировать. - person ChrisWue; 26.04.2011
comment
Абсолютно. Итак, далее: посмотрите в окно вывода отладки. Перейдите в раздел Отладка › Windows › Вывод. Если привязка не удалась, там будет строка, предупреждающая вас... - person kiwipom; 26.04.2011
comment
Итак, я сделал то, что вы сказали, и когда я открыл окно, в котором я пытаюсь применить это, я получил следующую ошибку: Ошибка System.Windows.Data: 40: Ошибка пути BindingExpression: свойство «Категории». не найден в объекте ''DataTest' (HashCode=40007697)'. BindingExpression:Path=Категории; DataItem='DataTest' (HashCode=40007697); целевой элемент — «ListView» (Name = «listView»); целевое свойство — «ItemsSource» (тип «IEnumerable»). - person Miguel; 26.04.2011
comment
Хорошо, я нашел проблему, в моем реальном случае у меня есть «Категории», а не «Категории», но в любом случае, когда я меняю (например, вставляю одно значение) значение, он не обновляет мой ListView... И PropertyChanged кадры Нуль... - person Miguel; 26.04.2011
comment
@Miguel - Просто чтобы проверить это - Установите тип свойства «Категории» на «Список‹строка»›; затем в конструкторе класса DataTest создайте новую строку List‹string›, поместите туда несколько фиктивных значений, например Red, White и Blue (подойдет что угодно) и установите свойство. Появляется ли список строк в вашем ListView? - person kiwipom; 26.04.2011
comment
С DataView он уже отображает содержимое моего DataView в ListView, но PropertyChanged по-прежнему имеет значение Null. - person Miguel; 26.04.2011
comment
Экземпляр «dataTest» в обработчике нажатия кнопки — это тот же экземпляр, который устанавливается в качестве DataContext? Это должно быть... - person kiwipom; 26.04.2011
comment
Я обновил свой вопрос, указав часть, в которой я установил класс как DataContext... - person Miguel; 26.04.2011
comment
@Miguel: если вы хотите, чтобы ListView обновлялся при добавлении/изменении элементов в вашем DataView, тогда DataView необходимо реализовать INotifyCollectionChanged. Прямо сейчас ListView будет обновляться только тогда, когда вы фактически замените категории совершенно другим объектом. Вероятно, вы захотите ознакомиться с этим руководством по привязке WPF: msdn.microsoft.com /en-us/library/ms752347.aspx - person ChrisWue; 26.04.2011
comment
Я обновил свой вопрос с помощью INotifyCollectionChanged. Можете ли вы проверить, что я делаю неправильно? - person Miguel; 26.04.2011

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

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

person Craig Suchanec    schedule 26.04.2011
comment
Итак, в этом случае, что я должен делать? - person Miguel; 26.04.2011
comment
Что вы хотите, чтобы произошло под вашим контролем? В большинстве случаев вы не создаете привязку после нажатия кнопки, а создаете привязку в XAML. Если у вас есть ListBox и вы хотите связать с ним категории, вы должны сделать ‹ListBox ItemsSource={Binding Categories}/›, предполагая, что ваш DataContext установлен как объект DataTest, которым вы хотите заполнить ItemsSource. Скорее всего, вам нужен какой-то способ предоставить текущий DataTest для XAML (возможно, DependencyProperty) и выполнить привязку на основе этого свойства. - person Craig Suchanec; 26.04.2011
comment
Я никогда не использовал свойства зависимостей. У меня есть небольшое представление о том, что они собой представляют, но я никогда не использовал. Я представил свою реальную ситуацию ниже в комментарии к другому ответу. - person Miguel; 26.04.2011

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

person Rick Sladkey    schedule 26.04.2011
comment
Итак, мой случай следующий... Я обновляю этот DataView, например, делаю запрос и помещаю данные в DataView, и значение свойства изменилось, но событие PorpertyChanged всегда равно null!! Почему? Мне нужно сделать что-то еще с PropertyChanged, но я не могу понять, что и где... Это моя проблема. Представьте, что я нажал кнопку, а затем изменил значение этого свойства, что мне делать дальше? - person Miguel; 26.04.2011
comment
Если PropertyChanged равно null, это означает, что нет клиентов, прослушивающих событие. Почему это было бы трудно сказать без дополнительной информации. - person Rick Sladkey; 26.04.2011
comment
Это как-то связано с привязками? Я привязываю свойство более чем в одном месте, поэтому я не думаю, что это связано с привязками. Я должен сделать что-то еще, но не могу понять, что... Должен ли я сделать что-то вроде этого dtTest.PropertyChanged = ? ??? - person Miguel; 26.04.2011
comment
Отредактируйте свой вопрос с помощью небольшого примера, демонстрирующего вашу проблему. - person Rick Sladkey; 26.04.2011
comment
Я отредактировал свое событие Button_Click, чтобы дать лучшее объяснение. Итак, я думаю, что мне нужно прикрепить какой-нибудь обработчик к моему PropertyChanged или что-то сделать с ним в моем окне, чтобы он не был NULL, верно? Но что? - person Miguel; 26.04.2011
comment
Кажется, вам не хватает того, что PropertyChanged существует ровно для одной цели: для поддержки привязки данных. В приведенном выше примере вы не показываете код привязки данных. - person Phil Sandler; 26.04.2011
comment
Я только что снова прочитал ваши комментарии - я думаю, вам нужно прочитать о привязке данных, о том, как она используется и т. д. Привязка данных к XAML - это то, для чего предназначено событие PropertyChanged. Если вы устанавливаете свойство «Категории» в своем коде, вы НЕ выполняете привязку данных. - person Phil Sandler; 26.04.2011
comment
Итак, как я могу делать свои свойства всякий раз, когда они изменяются, обновлять места, где они привязаны, чтобы отображать новые значения? - person Miguel; 26.04.2011
comment
@Miguel: Кроме того, как только вы получите работающие уведомления, static вызовет у вас некоторые проблемы. - person Rick Sladkey; 26.04.2011
comment
Я отредактировал свой вопрос, указав пример того, как я работаю в ListView, например... - person Miguel; 26.04.2011
comment
Прости. Со статическим я только что делал раньше, привязывая статический ресурс. Но мне нужно обновить все места, например, когда я добавляю новые значения в коллекцию. Но я не могу понять, как это работает. - person Miguel; 26.04.2011
comment
@Miguel: Похоже, у вас есть несколько объектов dtTest, и вы их путаете. Вам нужно обновить тот же, на который ссылается привязка. - person Rick Sladkey; 26.04.2011
comment
Хорошо, поэтому я спрашиваю, какой лучший подход к моей проблеме? После того, как я попробовал реализовать INotifyPropertyChange, я работал только со статическими свойствами, но они были доступны где угодно. Но что мне теперь делать? - person Miguel; 26.04.2011
comment
@Miguel: Databinding и INotifyPropertyChanged отлично работают, все их используют. Вам просто нужно научиться их использовать, но эти вещи требуют времени. Мы можем помочь, если у вас есть конкретная проблема. - person Rick Sladkey; 26.04.2011
comment
Хорошо, я могу опубликовать еще немного кода, чтобы объяснить лучше. Но что я делаю, так это то, что у меня есть главное окно, в котором у меня есть DataGrid, в котором будет отображаться таблица. Таким образом, некоторые из столбцов в DataGrid — это DataGridComboBoxColumn, и их заполняют DataViews. Так что есть одно место, где их использовать. И затем у меня есть другое окно для управления категориями, местами, поставщиками и т. Д. И в этих окнах у меня есть ListViews, которые я заполняю их DataViews. Поэтому я ищу лучший способ, когда я добавляю больше категорий в DataView, и после того, как я выполнил запрос на его обновление, я обновляю значения везде. - person Miguel; 26.04.2011