• DynamicObject 在WPF 中的应用


    在.Net Framework 4引入了dynamic关键字。它是在运行时才确定对象的类型。在运行的时候确定类型的好处是,少了一些装箱,拆箱操作。

    WPF中也有动态对象概念,那就是DynamicObject,它继承于IDynamicMetaObjectProvider这个接口。DynamicObject这个类能实现动态的给属性赋值和取值。它提供给我们两个TrySetMemberTryGetMember方法。我们只要重写这两个方法,来设置我们需要的属性。

    我们自定义一个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;
        }
    代码下载


    作者:dingli
    出处:http://www.cnblogs.com/dingli/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Spring HandlerInterceptor的使用
    JAVE 视音频转码
    习课的redis配置记录
    原 HttpClient 4.3超时设置
    IPMI
    Tomcat redis 配置
    JVM route
    linux swap空间的swappiness=0
    【SSH三大框架】Hibernate基础第五篇:利用Hibernate完毕简单的CRUD操作
    英特尔高速存储技术
  • 原文地址:https://www.cnblogs.com/dingli/p/2548687.html
Copyright © 2020-2023  润新知