从模型中更新ViewModel属性的正确方法
我是WPF的新手。我的理解是模型中的数据发生了变化,它应该通知视图模型,视图将绑定到视图模型中的属性和事物。它是否正确?如果是这样,我一直在读,该模型应该实现INotifyPropertyChanged
,并且是这个样子从模型中更新ViewModel属性的正确方法
public class LoginModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public bool Authenticated { get; set; }
}
,并在我的ViewModel,我有一个属性“AuthResult”,即应该从Model属性得到更新“身份验证“
public partial class view1 : UserControl, INotifyPropertyChanged{
public bool AuthResult
{
get
{
return _authVal;
}
set
{
_authVal = value;
NotifyPropertyChanged("AuthResult");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
我知道这个当前的实现是不正确的。我发现,我应该从我的模型订阅到的PropertyChanged通知如下所示:
LoginModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(LoginModel_PropertyChanged);
void LoginModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if(e.PropertyName == "Authenticated")
{
//do something
}
}
我看不出这里的“AuthResult”属性应该被更新。我会在If语句中做些什么,如AuthResult = _model.Authenticated;
?
编辑:
和在我的构造?
LoginModel _model;
public view1(LoginModel model)
{
_model = model;
InitializeComponent();
}
如果模型实现了INotifyPropertyChanged接口,你可以直接从该视图绑定到它:
<Button Content="Button" IsEnabled="{Binding Authenticated}" />
注意,LoginModel类必须提高,只要通过身份验证的属性被设置为一个新的PropertyChanged事件值。
你也可以通过视图模型类暴露整个模型实体:
public class ViewModel
{
public ViewModel(LoginModel model)
{
Model = model;
}
public LoginModel Model { get; }
}
...并绑定到它是这样的:
<Button Content="Button" IsEnabled="{Binding Model.Authenticated}" />
它仍然是模型类必须实现INotifyPropertyChanged接口并引发更改通知。
另一种选择是视图模型将您希望能够从视图绑定到的模型类的任何属性进行包装。然后你绑定到反过来包装的模型类像这样的属性视图模型类的属性:
public class ViewModel
{
private readonly LoginModel _model;
public ViewModel(LoginModel model)
{
_model = model;
}
public bool AuthResult
{
get
{
return _model.Authenticated;
}
set
{
_model.Authenticated = value;
NotifyPropertyChanged("AuthResult");
}
}
}
<Button Content="Button" IsEnabled="{Binding AuthResult}" />
采用后一种方法的好处是,鉴于有在模型类不存在依赖关系。它仅与视图模型类绑定,这就是MVVM设计模式通常要实现的方式。
但是,如果您绑定到视图模型的(包装)属性,并且希望在设置模型类的属性时更新视图,则模型必须通知视图模型它已经以单向方式更改或另一个,即它必须提出某种事件或类似事件。这通常意味着实现INotifyPropertyChanged接口。然后视图模型可以订阅模型的PropertyChanged事件,提高了绑定属性的数据,只要更新模型,如自身的PropertyChanged事件:
public class ViewModel
{
private readonly LoginModel _model;
public ViewModel(LoginModel model)
{
if (model == null)
throw new ArgumentNullException("model");
_model = model;
_model.PropertyChanged += OnModelChanged;
}
private void OnModelChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Authenticated")
NotifyPropertyChanged("AuthResult");
}
public bool AuthResult
{
get
{
return _model.Authenticated;
}
set
{
_model.Authenticated = value;
NotifyPropertyChanged("AuthResult");
}
}
}
只需使用型号为成员的视图模型
public class ViewModel
{
private Model _myModel;
public Model MyModel
{
get { return _myModel; }
set
{
if (Equals(_myModel, value)) return;
_myModel = value;
NotifyPropertyChanged(nameof(MyModel));
}
}
}
然后在XAML可以绑定的Model
<CheckBox IsChecked="{Binding MyModel.Authenticated}" />
特性用这种方法你的ViewModel将 “建立” 在你的模型。
如果您不希望该模型实现INotifyPropertyChanged
而不是像前面的示例那样创建使用中的“Facade”类模型。
public class ModelFacade : INotifyPropertyChanged
{
private Model _myModel;
public bool Authenticated
{
get { return _myModel.Authenticated; }
set
{
_myModel.Authenticated = value;
NotifyPropertyChanged(nameof(Authenticated));
}
}
}
public class ViewModel
{
private ModelFacade _myModel;
public ModelFacade MyModel
{
get { return _myModel; }
set
{
if (Equals(_myModel, value)) return;
_myModel = value;
NotifyPropertyChanged(nameof(MyModel));
}
}
}
好了,然后就结合为MyModel财产的控制风景?我假设你离开NotifyPropertyChanged()不完整,它应该实际读取'NotifyPropertyChanged(“MyModel”)'? – ganjeii
此外,我正在寻找从模型中获得具体的“身份验证”属性,您的答案似乎不完整。但我有点理解你来自哪里。 – ganjeii
您可以在视图中绑定到'MyModel.Authenticated',或者在视图模型中创建一个包装属性:'public bool AuthResult {get {return MyModel.Authenticated; }'。在后一种情况下,您需要将'NotifyPropertyChanged(“AuthResult”)'添加到MyModel属性的设置器中。 – mechanic
这个答案最终回答了我的问题,再次感谢mm8。 – ganjeii
第二个选项不是MVVM - 它是“Facade” – Fabio