DynamicObject 在WPF 中的应用在.Net Framework 4引入了dynamic关键字。它是在运行时才确定对象的类型。在运行的时候确定类型的好处是,少了一些装箱,拆箱操作。 WPF中也有动态对象概念,那就是DynamicObject,它继承于IDynamicMetaObjectProvider这个接口。DynamicObject这个类能实现动态的给属性赋值和取值。它提供给我们两个TrySetMember和TryGetMember方法。我们只要重写这两个方法,来设置我们需要的属性。 我们自定义一个DynamicBindingProxy泛型类: public class DynamicBindingProxy<T> : DynamicObject, INotifyPropertyChanged { private static readonly Dictionary<string, Dictionary<string, PropertyInfo>> properties = new Dictionary<string, Dictionary<string, PropertyInfo>>();//存放T 的属性 private readonly T _instance; private readonly string _typeName; public DynamicBindingProxy(T instance) { _instance = instance; var type = typeof(T); _typeName = type.FullName; if (!properties.ContainsKey(_typeName)) SetProperties(type, _typeName); } private static void SetProperties(Type type, string typeName) { var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); var dict = props.ToDictionary(prop => prop.Name); properties.Add(typeName, dict); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (properties[_typeName].ContainsKey(binder.Name)) { result = properties[_typeName][binder.Name].GetValue(_instance, null); return true; } result = null; return false; } public override bool TrySetMember(SetMemberBinder binder, object value) { if (properties[_typeName].ContainsKey(binder.Name)) { properties[_typeName][binder.Name].SetValue(_instance, value, null); if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(binder.Name)); } return true; } return false; } public event PropertyChangedEventHandler PropertyChanged; } 定义一个我们需要的实体类: public class Person { public string Name { get; set; } public int Age { get; set; } public DateTime Birthday { get; set; } } 实现动态属性变更: public partial class MainWindow : Window { private Person _person; private DynamicBindingProxy<Person> _bindingProxy; public MainWindow() { InitializeComponent(); _person=new Person(){Name = "xiaoli",Age = 23,Birthday = DateTime.Now}; _bindingProxy=new DynamicBindingProxy<Person>(_person);//动态绑定实体属性 DataContext = _bindingProxy; } private void UpdateName(object sender, RoutedEventArgs e) { ((dynamic)_bindingProxy).Name = newText.Text; } } xaml: <Grid HorizontalAlignment="Left" VerticalAlignment="Top"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <UniformGrid Rows="4" Columns="2"> <TextBlock TextWrapping="Wrap"><Run Text="Name"/></TextBlock> <TextBox TextWrapping="Wrap" Text="{Binding Name}"/> <TextBlock TextWrapping="Wrap"><Run Text="Age"/></TextBlock> <TextBox TextWrapping="Wrap" Text="{Binding Age}"/> <TextBlock TextWrapping="Wrap"><Run Text="Birthday"/></TextBlock> <TextBox TextWrapping="Wrap" Text="{Binding Birthday}"/> </UniformGrid> <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Grid.Row="1" Margin="0,10,0,0"> <TextBox TextWrapping="Wrap" Margin="0,0,10,0" Width="150" Name="newText"/> <Button Content="Change Name" Click="UpdateName" /> </StackPanel> </Grid> 这样就保持了我们的Entity是一个POCO了。 很多时候,我们修改了我们的属性。这时候我们要知道这些属性是否被修改过了,即已经Dirty了。我们在我们定义的DynamicBindingProxy类中增加一个Changes集合来存储变更的属性。然后在重写的TrySetMember方法中增加那些被更改的属性。 public class DynamicBindingProxy<T> : DynamicObject, INotifyPropertyChanged { private static readonly Dictionary<string, Dictionary<string, PropertyInfo>> properties = new Dictionary<string, Dictionary<string, PropertyInfo>>();//存放T 的属性 private readonly T _instance; private readonly string _typeName; public Dictionary<string, object> Changes { get; private set; } //存储变更的属性
public bool IsDirty { get { return Changes.Count > 0; } } //重置脏数据 public void Reset() { Changes.Clear(); NotifyPropertyChanged("IsDirty"); } public DynamicBindingProxy(T instance) { _instance = instance; var type = typeof(T); _typeName = type.FullName; if (!properties.ContainsKey(_typeName)) SetProperties(type, _typeName); Changes = new Dictionary<string, object>(); } private static void SetProperties(Type type, string typeName) { var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); var dict = props.ToDictionary(prop => prop.Name); properties.Add(typeName, dict); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (properties[_typeName].ContainsKey(binder.Name)) { result = properties[_typeName][binder.Name].GetValue(_instance, null); return true; } result = null; return false; } public override bool TrySetMember(SetMemberBinder binder, object value) { if (properties[_typeName].ContainsKey(binder.Name)) { properties[_typeName][binder.Name].SetValue(_instance, value, null); Changes[binder.Name] = value; NotifyPropertyChanged(binder.Name); return true; } return false; } private void NotifyPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } public event PropertyChangedEventHandler PropertyChanged; }
代码下载 |
|