DynamicObject WPF에서의 응용
16024 단어 dynamic
WPF에도 동적 대상 개념이 있는데 그것이 바로 다이나믹Object이다. 이것은 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;
}
<!--
.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
//
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; }
-->
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
API의 데이터가 포함된 Nuxt 2 동적 사이트맵일부 데이터 세트/api에서 사이트맵을 동적으로 구축하려는 경우 이것이 적합합니다. nuxt 프로젝트에서 익스프레스 API를 활성화했는지 여부에 관계없이 이 쉬운 3단계 프로세스를 통해 원하는 결과를 얻을 수 있습니...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.