我如何在viewmodel中检测模型内部属性的变化
本文关键字:内部 模型 属性 变化 检测 viewmodel | 更新日期: 2023-09-27 18:10:37
我正在使用WPF MVVM, Caliburn Micro和WCF服务构建我的第一个生产应用程序。
我已经到了一个点,我需要我的ViewModel来跟踪在我的模型中的单个属性的变化。我给你们举个例子。我的虚拟机有这样的属性:
public OrdenesTransporteWCFModel OrdenTransporte { get; set; }
public List<EnumeradorWCFModel> TiposCarga { get; set; }
public List<EnumeradorWCFModel> TiposCamion { get; set; }
public List<EnumeradorWCFModel> MediosContacto { get; set; }
OrdenesTransporteWCFModel是一个来自WCF服务的模型,我的视图可能看起来像这样:
<ComboBox ItemsSource="{Binding Path=TiposCarga}" SelectedValuePath="ID" DisplayMemberPath="Descripcion" SelectedValue="{Binding Path=OrdenTransporte.ID_TipoCarga}"></ComboBox>
<ComboBox ItemsSource="{Binding Path=TiposCamion}" SelectedValuePath="ID" DisplayMemberPath="Descripcion" SelectedValue="{Binding Path=OrdenTransporte.ID_TipoMovil}"></ComboBox>
<ComboBox ItemsSource="{Binding Path=MediosContacto}" SelectedValuePath="ID" DisplayMemberPath="Descripcion" SelectedValue="{Binding Path=OrdenTransporte.ID_MedioContacto,ValidatesOnDataErrors=True}"></ComboBox>
<TextBox IsEnabled="False" Text="{Binding Path=OrdenTransporte.Numero}"></TextBox>
<DatePicker SelectedDate="{Binding Path=OrdenTransporte.FechaConfeccion}"></DatePicker>
正如你所看到的,我将控件绑定到我的模型(OrdenTransporte)中的单个属性。
现在我需要的是我的VM来跟踪这个属性的变化:例如,我在我的VM属性HasChange中有一个bool,如果任何字段发生了变化,我需要激活它。此外,我有一个方法TipoCamionChange,如果ID_TipoCamion属性改变,我需要触发。
我有什么办法可以做到吗?谢谢!
编辑
正如Martin建议的那样,我在我的模型上实现了INotifyPropertyChange,并尝试像这样将我的模型订阅到我的模型上的propertychange事件:
OrdenTransporte = _svc.OrdenesTransporte_GetById(IDOrden);
OrdenTransporte.PropertyChanged += Model_PropertyChanged;
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "ID_Cliente")
{
CargarDirecciones();
}
}
问题是,当我订阅我的vm模型PropertyChange时,模型中的数据已经发生了变化,因此PropertyChanged从未被调用。如果我这样做:
OrdenTransporte.PropertyChanged += Model_PropertyChanged;
OrdenTransporte = _svc.OrdenesTransporte_GetById(IDOrden);
无论如何都不会触发事件,因为整个对象被WCF服务(包括INotifyPropertyChange事件)返回的对象所替换。什么好主意吗?
模型类是否实现INotfiyPropertyChanged
?
然后,您可以在视图模型中设置事件处理程序以响应模型类中的更改:
modelObject.PropertyChanged += ViewModelOnPropertyChanged;
private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
// react to object change here
}
您可以将多个模型对象的事件链接到同一个事件处理程序,然后设置您的HasChange
视图模型属性。
如果你的模型对象不实现INotfiyPropertyChanged
我不知道一个解决方案。
您可以使用Dynamic Castle(它将实例封装在代理中)或Fody(它在编译时的后期步骤中修改IL)自动为模型属性添加IPNC支持。
更新:如果你的模型来自一个web服务引用,那么他们已经有IPCN支持,你可以通过在你的项目中自动生成的源代码看到这一点。您也可以在代码中进行确认:
using (var client = new ServiceReference1.Service1Client())
{
var data = client.GetData();
data.PropertyChanged += (s, e) =>
{
Debug.Assert(false, "PropertyChanged handler invoked.");
};
data.SomeMember = false; // <-- will cause the assert to trigger
}
您应该使用ObservableCollection<T>
而不是List<T>
和INotifyPropertyChanged。
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private ObservableCollection<EnumeradorWCFModel> _tiposCarga;
public ObservableCollection<EnumeradorWCFModel> TiposCarga
{
get { return _tiposCarga; }
set
{
if (_tiposCarga != value)
{
_tiposCarga = value;
OnPropertyChanged(nameof(TiposCarga));
}
}
}