我正在使用 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) 内的各个属性。
现在我需要的是我的虚拟机来跟踪此属性的更改:例如,我的虚拟机属性HasChange中有一个布尔值,如果任何字段发生更改,我需要激活它。另外,我还有一个方法 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();
}
}
问题是,当我将虚拟机订阅到模型PropertyChange时,模型中的数据已经发生变化,因此PropertyChanged永远不会被调用。如果我这样做:
OrdenTransporte.PropertyChanged += Model_PropertyChanged;
OrdenTransporte = _svc.OrdenesTransporte_GetById(IDOrden);
事件无论如何都不会被触发,因为整个对象都被 WCF 服务返回的对象所替换,包括 INotifyPropertyChange 事件。有什么想法吗?
模型类是否实现了
INotifyPropertyChanged
?
然后您可以在视图模型中针对模型类中的更改设置事件处理程序:
modelObject.PropertyChanged += ViewModelOnPropertyChanged;
private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
// react to object change here
}
您可以将多个模型对象的事件全部链接到同一个事件处理程序,然后设置您的
HasChange
视图模型属性。
如果你的模型对象没有实现
INotifyPropertyChanged
我不知道解决方案。
您可以使用 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));
}
}
}