对象属性的RaisePropertyChanged

3

我有一个用户模型:

public class User
{
    public string Name { get; set; }
    public int Level { get; set; }
}

视图中:

<TextBox Text="{Binding NewUser.Name}"/>
<TextBox Text="{Binding NewUser.Level}"/>

以及虚拟机中的属性:

public User NewUser
    {
        get { return _newUser; }
        set
        {
            if (_newUser == value)
                return;
            _newUser = value;
            RaisePropertyChanged("NewUser");
        }
    }

这段代码更新了属性:

NewUser = new User() { Name = "test", Level = 1 };

而这段代码则没有更新属性:

NewUser.Name = "test";

你做错了什么?你正在使用MVVM Light。

2个回答

2

当设置 NewUser.Name 时,ViewModel 上的 RaisePropertyChanged 不会被调用,因此不会触发 PropertyChangedEvent

通常情况下,你应该有充分的理由直接在 ViewModel 中公开模型类,就像你在这里一样(在你的 ViewModel 中公开一个 User 模型作为公共属性)。这基本上违反了 Models 和 ViewModels 之间的关注点分离,而 MVVM 就是为此而设计的。尽管这看起来很学术,但我的经验是,在大多数实际情况下,ViewModels 往往随着时间的推移变得更加复杂,并包含您不希望出现在模型中的功能(比如 INPC 实现,顺便说一句)。

虽然它需要更多的编码工作,但你应该在这里实现一个嵌套的 ViewModel。这里有一些代码可以让你开始:

public class ParentViewModel : NotifyingObject
{
    private UserViewModel _user;

    // This is the property to bind to
    public UserViewModel User
    {
        get { return _user; }
        private set
        {
            _user = value;
            RaisePropertyChanged(() => User);
        }
    }

    public ParentViewModel()
    {
        // Wrap the new instance in a ViewModel
        var newUser = new User {Name = "Test"};
        User = new UserViewModel(newUser);
    }
}

这是额外的ViewModel,其中包装了User模型类:

public class UserViewModel : NotifyingObject
{
    /// <summary>
    /// The model is private here and not exposed to the view
    /// </summary>
    private readonly User _model;

    public string Name
    {
        get { return _model.Name; }
        set
        {
            _model.Name = value;
            RaisePropertyChanged(() => Name);
        }
    }       

    public UserViewModel(User model)
    {
        _model = model;
    }
}

这是您的模型类。无需实现INotifyPropertyChanged

public class User
{
    public string Name { get; set; }
}

1
你的 User 类没有实现 INotifyPropertyChanged 接口。因此,通过赋值更改属性 NewUser 将触发 UI,而通过赋值设置属性 Name 则不会。
如果按照您的模式进行操作,那么这样:
public string Name { get; set; }

最终应该是这个样子:

应该最终看起来像这样:

public string Name
{
    get { return _name; }
    set
    {
        if (_name == value)
            return;
        _name = value;
        RaisePropertyChanged("Name");
    }
}

你能否提供一个示例,展示我的“User”类应该是什么样子的? - el-nino
你已经在具有NewUser属性的类中实现了INotifyPropertyChanged。只需以相同的方式在User类中实现即可。没有一种完美的方法,你应该始终使用相同的方式。只需查看具有NewUser属性的类即可。 - nvoigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接