MVVM Light - Невозможно обновить родительское представление из вложенного редактирования. - PullRequest
0 голосов
/ 23 февраля 2012

Моя ситуация немного отличается от других постов, и я не смог решить ее с другими тредами. Так вот почему я спрашиваю.

У меня есть класс, полученный в результате десериализации XML, например:

<?xml version="1.0" encoding="UTF-8"?>
<node>
    <leaf>
        <name>node 1</name>
        <text>text 1</text>
        <url>url 1</url>
    </leaf>
    <leaf>
        <name>node 2</name>
        <text>text 2</text>
        <url>url 2</url>
    </leaf>
</node>

так что класс:

[XmlRoot("node")]
public class csNodeList
{
    public csNodeList()
    {
        Leaf = new csLeafCollection();
    }

    [XmlElement("leaf")]
    public csLeafCollection Leaf
    {
        get;
        set;
    }
}

public class csLeaf
{
    public csLeaf()
    {
        Name ="";
        Description = "";
        Address = "";
    }

    [XmlElement("name")]
    public string Name
    {
        get;
        set;
    }

    [XmlElement("text")]
    public string Description
    {
        get;
        set;
    }

    [XmlElement("url")]
    public string Address
    {
        get;
        set;
    }
}

public class csLeafCollection : System.Collections.ObjectModel.ObservableCollection<csLeaf>
{
}

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

Для этого я копирую объекты в резервную переменную, а затем изменяю объекты, связанные с помощью привязки к представлению XAML, таким образом (теоретически) должно отражаться любое изменение данных ViewModel. Также лучше, потому что, если я фиксирую изменения, я просто отбрасываю резервные переменные (это 90% времени) и, если мне нужно откатиться, я копирую обратно из резервных переменных.

MainView:

public const string listPropertyName = "list";
private csNodeList _list = new csNodeList();
public csNodeList list
{
    get
        {
        return _list;
    }
    set
    {
        Set(listPropertyName, ref _list, value, false);
    }
}

Используя сообщение, я отправляю обратно новые значения узла и помещаю их в правильную позицию:

private void DoSomething(csMessage message)
{
    csMessage rmessage;
    if (message != null)
    {
        switch (message.destination)
        {
            case csMessage.e2MessageDest.updateNode:
            //_editP should be fine.
            list.Leaf[list.Leaf.IndexOf(_editP)].Name = ((csLeaf)message.payload).Name;
            list.Leaf[list.Leaf.IndexOf(_editP)].Text= ((csLeaf)message.payload).Text;
            list.Leaf[list.Leaf.IndexOf(_editP)].Address = ((csLeaf)message.payload).Address;
            RaisePropertyChanged(listPropertyName , null, _list, true);
            break;
        }
    }
}

Код выполнен правильно и элемент изменен.

НО RaisePropertyChanged игнорируется. Я пробовал даже только один с listPropertyName без каких-либо изменений.

Если я сохраняю изменения, выход из приложения и возвращаюсь, я вижу, что новое значение правильно сохранено

Не могли бы вы мне помочь?

Спасибо, Massimo

Ответы [ 2 ]

0 голосов
/ 25 февраля 2012

Спасибо всем за помощь. Исследуя ваше предложение, я нашел немного другое решение; как вы правильно сказали, проблема в том, что конечные поля не являются "наблюдаемыми", поэтому они не генерируют событие уведомления.

Я заметил, что если я добавляю или удаляю профиль, привязка обновляется.

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

Вот что я делаю:

        csLeaf _leaf = new slLeaf();
        _leaf.Name = ((csLeaf)message.payload).Name; 
        _leaf.Text= ((csLeaf)message.payload).Text; 
        _leaf.URL = ((csLeaf)message.payload).Address; 
        list.Leaf[list.Leaf.IndexOf(_editP)] = _leaf;

Для оптимизации читабельности кода я улучшил его, добавив конструктор с 3 параметрами, чтобы код мог быть:

        csLeaf _leaf = new slLeaf(((csLeaf)message.payload).Name, ((csLeaf)message.payload).Text, ((csLeaf)message.payload).Address);
        list.Leaf[list.Leaf.IndexOf(_editP)] = _leaf;

Конструктор:

public csLeaf(string _name, string _description, string _address) 
{ 
    Name = _name; 
    Description = _description;
    Address = _address; 
} 
0 голосов
/ 23 февраля 2012

Причина, по которой ваш RaisePropertyChanged игнорируется, заключается в том, что класс листьев не реализует INotifyOropertyChanged.Обычно модель оборачивается в модель представления, которая затем реализует INotifyPropertyChange d, чтобы уведомить представление о том, что произошло.

Однако вы также можете напрямую реализовать INotifyPropertyChanged в классе модели.Для реализации INotifyPropertyChanged каждое свойство должно вызывать событие измененного свойства.

public string Property {
    get { ... }
    set {
        if (_propertyField == value)
            return;
        _propertyField = value;
        RaisePropertyChanged("Property");
    }
}

Код предполагает, что существует метод RaisePropertyChanged, который фактически использует PropertyChangedEvent.

...