zoukankan      html  css  js  c++  java
  • 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/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    [转]asp.net页面缓存技术
    UL和LI在div中的高度的IE6下兼容性
    jquery制作的横向图片滚动带横向滚动条TackerScroll
    电脑可以上网,但是qq登陆不上去?
    Introduction to discrete event system学习笔记4.6
    Introduction to Discrete event system学习笔记4.9
    Introduction to discrete event systemsstudy 4.5
    Symbolic synthesis of obserability requirements for diagnosability B.Bittner,M.Bozzano,A.Cimatti,and X.Olive笔记4.16
    Introduction to discrete event system学习笔记4.8pm
    Introduction to discrete event system学习笔记 4.8
  • 原文地址:https://www.cnblogs.com/dingli/p/2548687.html
Copyright © 2011-2022 走看看