我正在尝试在下面的代码中为用例创建代码,其中一般的ViewModel类“捕获”其模型中的所有属性,并呈现具有相同名称和类型的属性,并且还触发数据的PropertyChanged
事件 - 捆绑。
有办法吗?我正在使用.NET 4.6。
public class Rectangle
{
public double Width {get; set;}
public double Height {get; set;}
}
public class RectangleViewModel : MagicViewModel<Rectangle>
{
public RectangleViewModel(Rectangle model)
: base(model){ }
}
public class MagicViewModel<TModel> : INotifyPropertyChanged
{
protected readonly TModel _model;
public MagicViewModel(TModel model)
{
_model = model;
}
// inpc implementation
// what else?
}
public class Program
{
public static void Main(string[] args)
{
var vm = new RectangleViewModel(new Rectangle());
var calls = 0;
vm.PropertyChanged += (sender, args) => calls++;
vm.Height = 10; // magic happened here
Debug.Assert(calls > 0);
}
}
您可以使用Fody自动注入代码,以便在编译时为模型类的所有属性引发PropertyChanged
事件。
然后你可以直接绑定到Rectangle
而不修改它并显式实现INotifyPropertyChanged
接口。
否则,我担心您必须在每个视图模型中逐个定义每个属性,或者在构建之前想出一种自动生成视图模型类的方法。
你正在寻找的是这样的东西吗?
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
public class Rectangle : INotifyPropertyChanged
{
private double height;
public double Width { get; set; }
public double Height { get => height; set => SetField(ref height, value); }
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
public class RectangleViewModel : MagicViewModel<Rectangle>
{
public RectangleViewModel(Rectangle model)
: base(model)
{
this.model = model;
model.PropertyChanged += (s, e) => OnPropertyChanged(e.PropertyName);
}
private Rectangle model;
public Rectangle Model { get => model; set => SetField(ref model, value); }
}
public class MagicViewModel<TModel> : INotifyPropertyChanged
{
protected readonly TModel _model;
public MagicViewModel(TModel model)
{
_model = model;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
#endregion
}
public class Program
{
public static void Main(string[] args)
{
var vm = new RectangleViewModel(new Rectangle());
var calls = 0;
vm.PropertyChanged += (sender, propChangedArgs) => calls++;
vm.Model.Height = 10; // magic happened here
Debug.Assert(calls > 0);
}
}