INotifyPropertyChanged не работает для сериализации XML - PullRequest
0 голосов
/ 18 апреля 2011

У меня есть DataGridView, который связан с коллекцией. Типы в коллекции реализуют INotifyPropertyChanged (реализация учебника со страницы MSDN).

public event PropertyChangedEventHandler PropertyChanged;

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

public string Name
    {
    get { return m_Name; }
    set { m_Name = value; NotifyPropertyChanged("Name"); }
    }

Я пытаюсь понять, когда, как и почему происходит событие PropertyChanged. Если я пишу код для использования свойства Name для изменения строки, все работает, PropertyChanged имеет значение! = NULL, и мой DataGridView обновляется правильно. Вот так:

for (int i = 0; i < Server.Customers.Count; i++)
    {
    Server.Customers[i].Name = Server.Customers[i].Name + "!!";
    }

Это всего лишь тест, однако способ, которым коллекция должна действительно обновляться, - десериализация XML. Реализация для сериализатора очень проста, и код выполняет то же свойство Name (вызывая NotifyPropertyChanged), что и в предыдущем примере. С одним отличием: PropertyChanged оказывается равным NULL и никогда не вызывается. Результат: в моей привязке данных нет обновлений.

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

Ответы [ 3 ]

1 голос
/ 18 апреля 2011

Я полностью согласен с ответом Томаса и добавляю несколько предложений:

Если вам нужно использовать INotifyPropertyChanges, вам определенно следует пойти другим путем для десериализации объекта.Вы можете использовать метод экземпляра, например InitializeFrom(string xml) или UpdateFrom(string xml).Вы создаете объект, подписываетесь на событие PropertyChanged, а затем вы вызываете UpdateFrom(xml) для существующего объекта.Таким образом, вы будете уведомлены об изменениях и сохраните существующий объект живым.Здесь вы можете реализовать все это следующим образом:

class MyClass : INotifyPropertyChanges
{
    private void NotifyPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    public string Name
    {
        get { return m_Name; }
        set { m_Name = value; NotifyPropertyChanged("Name"); }
    }

    public void UpdateFrom(string xml)
    {
        MyClass deserialized = Deserialize(xml);

        // here you set all properties you have
        Name = deserialized.Name;
        // and all the rest properties...
    }

    private static MyClass Deserialize(string xml)
    {
        XmlSerializer ser = new XmlSerializer(typeof(MyClass));
        using (StringReader reader = new StringReader(xml))
        {
            return (MyClass)ser.Deserialize(reader);
        }
    }
}

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

1 голос
/ 18 апреля 2011

XML-сериализация не может обновить существующий объект, она всегда создает новый при десериализации. Поскольку это новый объект, для PropertyChanged еще нет обработчика, поэтому событие не вызывается.

Нет смысла слушать PropertyChanged событие создаваемого объекта. Что именно ты пытаешься сделать?

0 голосов
/ 27 июля 2011

У меня была похожая проблема здесь , поскольку я действительно не хотел обновлять каждое свойство в отдельности, мне удалось решить его, выполнив DataContext = (Настройки) bf.Deserialize (oS);где «Настройки» - это мой вид модели, который выполняет свойства propertyChanged, «bf» - мой xmlserializer, а «oS» - мой файловый поток.

...