DynamicObject WPF에서의 응용

16024 단어 dynamic
에 있습니다.Net Framework 4에는 dynamic 키워드가 도입되었습니다.이것은 실행할 때 비로소 대상의 유형을 확정한다.운행할 때 유형을 정하는 장점은 포장이 적고 뜯는 작업이 적다는 것이다.
WPF에도 동적 대상 개념이 있는데 그것이 바로 다이나믹Object이다. 이것은 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;

    }

<!--
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
-->
필요한 솔리드 클래스를 정의합니다.
public class Person

    {

        public string Name { get; set; }

        public int Age { get; set; }

        public DateTime Birthday { get; set; }

    }

<!--
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
-->
동적 속성 변경 구현:
 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;

        }



    }

<!--
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
-->
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>

<!--
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
-->
이렇게 하면 우리의 Entity는 하나의 POCO를 유지할 수 있다.
많은 경우에 우리는 우리의 속성을 수정했다.이때 우리는 이 속성들이 수정되었는지, 즉 이미dirty가 되었는지 알아야 한다.변경된 속성을 저장하기 위해 DynamicBindingProxy 클래스에 변경 사항 집합을 추가합니다.그리고 다시 쓰는 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 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;

    }

 
코드 다운로드

<!--
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
-->

좋은 웹페이지 즐겨찾기