ding.li 发表于 2012-12-19 21:12:50

DynamicObject 在WPF 中的应用

<div id="cnblogs_post_body">在.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.ContainsKey(binder.Name))            {                result = properties.GetValue(_instance, null);                return true;            }            result = null;            return false;      }      public override bool TrySetMember(SetMemberBinder binder, object value)      {            if (properties.ContainsKey(binder.Name))            {                properties.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"><RunText="Name"/></TextBlock>                  <TextBox TextWrapping="Wrap" Text="{Binding Name}"/>                  <TextBlock TextWrapping="Wrap"><RunText="Age"/></TextBlock>                  <TextBox TextWrapping="Wrap" Text="{Binding Age}"/>                  <TextBlock TextWrapping="Wrap"><RunText="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.ContainsKey(binder.Name))            {                result = properties.GetValue(_instance, null);                return true;            }            result = null;            return false;      }      public override bool TrySetMember(SetMemberBinder binder, object value)      {            if (properties.ContainsKey(binder.Name))            {                properties.SetValue(_instance, value, null);                Changes = 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;    }
代码下载
页: [1]
查看完整版本: DynamicObject 在WPF 中的应用