MVVM Light - 无法从子嵌套编辑更新父视图

时间:2012-02-22 23:23:43

标签: binding mvvm-light parent-child messaging

我的情况与其他帖子略有不同,我无法用其他trhread解决它。那就是我问的原因。

我有一个通过反序列化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的那个没有任何改变。

如果我保存更改退出应用并退回,我会看到正确存储的新值

你能帮帮我吗?

谢谢, 马西莫

2 个答案:

答案 0 :(得分:0)

你的RaisePropertyChanged被忽略的原因是叶子类没有实现INotifyOropertyChanged。通常,模型被包装到视图模型中,然后实现INotifyPropertyChange d以通知视图已发生的事情。

但是,您也可以直接在模型类上实现INotifyPropertyChanged。要实现INotifyPropertyChanged,每个属性都必须提升propty更改事件。

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

代码假定有一个方法RaisePropertyChanged实际上会使PropertyChangedEvent加密。

答案 1 :(得分:0)

谢谢大家的帮助。 调查你的建议我发现了一个稍微不同的解决方案;正确地说,问题是叶子字段不是“可观察的”,因此它们不会生成通知事件。

我注意到如果添加或删除配置文件,绑定会更新。

所以我决定做的不是直接编辑叶子而是替换节点。 我不喜欢的是我必须创建一个节点来替换旧的节点,这会分配更多的内存......但对于我所拥有的小数据,它可以在不对app性能产生任何重大影响的情况下工作记忆足印。

以下是我的工作:

        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; 
}