我如何在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事件)返回的对象所替换。什么好主意吗?

我如何在viewmodel中检测模型内部属性的变化

模型类是否实现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));
        }
    }
}