如何在viewmodel中检测模型内属性的更改?

时间:2015-08-30 14:54:27

标签: c# wpf mvvm

我使用WPF MVVM,Caliburn Micro和WCF服务来构建我的第一个生产应用程序。

我已经到了需要我的ViewModel来跟踪模型中各个属性的变化的地步。我举个例子。我的VM具有以下属性:

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事件。任何想法?

3 个答案:

答案 0 :(得分:1)

模型类是否实现***

然后,您可以在视图模型中将事件处理程序设置为模型类中的更改:

INotfiyPropertyChanged

您可以将多个模型对象的事件全部链接到同一个事件处理程序,然后设置 modelObject.PropertyChanged += ViewModelOnPropertyChanged; private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { // react to object change here } 视图模型属性。

如果您的模型对象未实现HasChange,我不知道解决方案。

答案 1 :(得分:1)

您可以使用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
}

答案 2 :(得分:0)

您应该使用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));
        }
    }
}