支持了多级绑定

This commit is contained in:
飞色 开 2023-11-27 15:57:46 +08:00
parent 7b64b82032
commit 6d5acbdfac
7 changed files with 173 additions and 320 deletions

View File

@ -12,6 +12,7 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading; using System.Threading;
using System.Diagnostics;
namespace CPF namespace CPF
{ {
@ -366,29 +367,21 @@ namespace CPF
} }
return; return;
} }
//CpfObject s = Source.Target as CpfObject; /*var SourcePropertyNames = SourcePropertyName.Split('.');
//if (s == null) if (SourcePropertyNames.Length > 1) {
//{ value = Source.Target;
// var p = Source.Target.GetType().GetProperty(SourcePropertyName); for (int i = 0; i < SourcePropertyNames.Length; i++)
// if (p == null) {
// { value = value.GetPropretyValue(SourcePropertyNames[i]);
// throw new Exception("未找到" + Source.Target + "的属性:" + SourcePropertyName); }
// } }
// value = p.FastGetValue(Source.Target); else
//} {
//else
//{
// if (s.HasProperty(SourcePropertyName))
// {
// value = s.GetValue(SourcePropertyName);
// }
// else
// {
// var p = s.Type.GetProperty(SourcePropertyName);
// value = p.FastGetValue(Source.Target);
// }
//}
value = Source.Target.GetPropretyValue(SourcePropertyName); value = Source.Target.GetPropretyValue(SourcePropertyName);
}*/
value = GetPropertySource(SourcePropertyName, Source.Target);
value = value.GetPropretyValue(SourcePropertyName.Split('.').LastOrDefault());
if (Convert != null) if (Convert != null)
{ {
value = Convert(value); value = Convert(value);
@ -453,9 +446,19 @@ namespace CPF
{ {
if (!b.SetValue(nv, SourcePropertyName)) if (!b.SetValue(nv, SourcePropertyName))
{ {
//b.Type.GetProperty(SourcePropertyName).FastSetValue(b, nv); var SourcePropertyNames = SourcePropertyName.Split('.');
if (SourcePropertyNames.Length == 1)
{
b.SetValue(SourcePropertyName, nv); b.SetValue(SourcePropertyName, nv);
} }
var Target = b;
for (int i = 0; i < SourcePropertyNames.Length-1; i++)
{
Target = Target.GetPropretyValue(SourcePropertyNames[i]) as CpfObject;
}
Target.SetValue(nv, SourcePropertyNames.LastOrDefault());
//b.Type.GetProperty(SourcePropertyName).FastSetValue(b, nv);
}
} }
else else
{ {
@ -533,7 +536,8 @@ namespace CPF
} }
void PropertyChanged(object sender, PropertyChangedEventArgs e) void PropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (SourcePropertyName == e.PropertyName) var Temp_SourcePropertyName = SourcePropertyName.Split('.').LastOrDefault();
if (Temp_SourcePropertyName == e.PropertyName)
{ {
//CPFObject s = sender as CPFObject; //CPFObject s = sender as CPFObject;
//object value; //object value;
@ -557,6 +561,27 @@ namespace CPF
} }
} }
} }
internal object GetPropertySource(string SourcePropertyName,object Source)
{
try
{
var SourcePropertyNames = SourcePropertyName.Split('.');
if (SourcePropertyNames.Length == 1)
{
return Source;
}
var Target = Source;
for (int i = 0; i < SourcePropertyNames.Length - 1; i++)
{
Target = Target.GetPropretyValue(SourcePropertyNames[i]) as CpfObject;
}
return Target;
}
catch (Exception ex)
{
throw new Exception("错误:{ex}");
}
}
internal void RegisterPropertyChanged(INotifyPropertyChanged notify) internal void RegisterPropertyChanged(INotifyPropertyChanged notify)
{ {
@ -564,7 +589,8 @@ namespace CPF
//{ //{
// throw new Exception("错误"); // throw new Exception("错误");
//} //}
RegisterPropertyChanged(notify, PropertyChanged); var notifySource = GetPropertySource(this.SourcePropertyName, notify);
RegisterPropertyChanged(notifySource as INotifyPropertyChanged, PropertyChanged);
} }
internal void CancellationPropertyChanged(INotifyPropertyChanged notify) internal void CancellationPropertyChanged(INotifyPropertyChanged notify)
{ {

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.ComponentModel; using System.ComponentModel;
using System.Linq.Expressions;
namespace CPF namespace CPF
{ {
@ -16,6 +17,7 @@ namespace CPF
{ {
PropertyName = sourceProperty; PropertyName = sourceProperty;
} }
public BindingDescribe(string sourceProperty, BindingMode binding) public BindingDescribe(string sourceProperty, BindingMode binding)
{ {
PropertyName = sourceProperty; PropertyName = sourceProperty;

View File

@ -7,6 +7,7 @@ using System.Linq;
using CPF.Controls; using CPF.Controls;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using System.Diagnostics;
namespace CPF namespace CPF
{ {
@ -102,6 +103,7 @@ namespace CPF
else else
{ {
//((INotifyPropertyChanged)source).PropertyChanged += b.PropertyChanged; //((INotifyPropertyChanged)source).PropertyChanged += b.PropertyChanged;
b.RegisterPropertyChanged((INotifyPropertyChanged)source); b.RegisterPropertyChanged((INotifyPropertyChanged)source);
b.SourceToTarget(); b.SourceToTarget();
} }
@ -114,6 +116,7 @@ namespace CPF
{ {
b.SourceToTarget(); b.SourceToTarget();
} }
//Debug.WriteLine($"sourcePropertyName:{sourcePropertyName},bindingMode:{bindingMode}");
return b; return b;
} }
/// <summary> /// <summary>

53
CPF/Obx.cs Normal file
View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace CPF
{
public class Obx<T>: BindingDescribe where T : CpfObject, new()
{
public Obx(Expression<Func<T, object>> sourceProperty)
{
var expression = GetMemberExpression(sourceProperty.Body);
PropertyName = GetMemberPath(expression);
}
public Obx(Expression<Func<T, object>> sourceProperty, BindingMode binding)
{
var expression = GetMemberExpression(sourceProperty.Body);
PropertyName = GetMemberPath(expression);
BindingMode = binding;
}
public Obx(Expression<Func<T, object>> sourceProperty, BindingMode binding, Func<object, object> convert)
{
var expression = GetMemberExpression(sourceProperty.Body);
PropertyName = GetMemberPath(expression);
BindingMode = binding;
Convert = convert;
}
private static MemberExpression GetMemberExpression(Expression expression)
{
if (expression is MemberExpression memberExpression)
{
return memberExpression;
}
else if (expression is UnaryExpression unaryExpression)
{
return (MemberExpression)unaryExpression.Operand;
}
else
{
throw new ArgumentException("Invalid expression. Expected a MemberExpression or UnaryExpression.");
}
}
private static string GetMemberPath(MemberExpression expression)
{
if (expression.Expression is MemberExpression memberExpression)
{
return GetMemberPath(memberExpression) + "." + expression.Member.Name;
}
return expression.Member.Name;
}
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net40;net5;net6</TargetFrameworks> <TargetFrameworks>netcoreapp3.0;net40;net5;net6;net8</TargetFrameworks>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>

View File

@ -3,11 +3,51 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using CPF.Controls; using CPF.Controls;
using static System.Net.Mime.MediaTypeNames;
namespace ConsoleApp1 namespace ConsoleApp1
{ {
public class data : CpfObject
{
public data test {
get
{
return (data)GetValue();
}
set
{
SetValue(value);
}
}
public data()
{
test = this;
}
[PropertyMetadata("我是默认的")]
public string Name
{
get
{
return (string)GetValue();
}
set
{
SetValue(value);
}
}
}
class MainModel : CpfObject class MainModel : CpfObject
{ {
public data Test1 {
get
{
return (data)GetValue();
}
set
{
SetValue(value);
}
}
[PropertyMetadata("默认值")] [PropertyMetadata("默认值")]
public string Test public string Test
{ {
@ -28,6 +68,7 @@ namespace ConsoleApp1
public MainModel() public MainModel()
{ {
Test1 = new data();
Items = new Collection<(string, string)>(); Items = new Collection<(string, string)>();
TestItems = new Collection<(string, int)>(); TestItems = new Collection<(string, int)>();

View File

@ -188,6 +188,7 @@ namespace ConsoleApp1
{ {
MarginTop = 0, MarginTop = 0,
Content = "点击生成pdf", Content = "点击生成pdf",
[nameof(Button.Content)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name),
Commands = Commands =
{ {
{ {
@ -235,7 +236,7 @@ namespace ConsoleApp1
Content="另外一个演示窗体😍", Content="另外一个演示窗体😍",
MarginTop=20, MarginTop=20,
MarginLeft=20, MarginLeft=20,
[nameof(Button.Click)]=(BindingDescribe)((s,e)=> [nameof(Button.Click)]=new CommandDescribe((s,e)=>
{ {
var w = new Window1(); var w = new Window1();
w.DataContext = model; w.DataContext = model;
@ -1386,7 +1387,8 @@ namespace ConsoleApp1
MarginTop = 76, MarginTop = 76,
Height = 23, Height = 23,
Width = 219, Width = 219,
[nameof(Slider.Value)]=new BindingDescribe(null, nameof(MainModel.ColumnWidth),BindingMode.OneWayToSource,null,a=>new GridLength((float)(double)a)) //[nameof(Slider.Value)]= new Obx<MainModel>(a => a.Type.Name),
[nameof(Slider.Value)]= new BindingDescribe(null, nameof(MainModel.ColumnWidth),BindingMode.OneWayToSource,null,a=>new GridLength((float)(double)a))
}, },
} }
} }
@ -2419,10 +2421,10 @@ new TabItemTemplate{
}, },
new TabItemTemplate new TabItemTemplate
{ {
Header="布局", Header="多级绑定",
Content=new Panel Content=new Panel
{ {
Name = "布局", Name = "多级绑定",
PresenterFor = this, PresenterFor = this,
Width="100%", Width="100%",
Height="100%", Height="100%",
@ -2435,306 +2437,32 @@ new TabItemTemplate{
Orientation= Orientation.Vertical, Orientation= Orientation.Vertical,
Children= Children=
{ {
new Button
{
Content="StackPanel的Vertical"
},
new Button
{
Content="按钮"
},
new Button
{
Content="按钮"
},
new Button
{
Content="按钮"
},
}
},
new StackPanel
{
BorderStroke = "5,Solid",
BorderFill = "#B4B4B4",
MarginLeft=80,
MarginTop=50,
Orientation= Orientation.Horizontal,
Children=
{
new Button
{
Content="StackPanel的Horizontal"
},
new Button
{
Content="按钮"
},
new Button
{
Content="Margin调间距",
MarginLeft=5
},
new Button
{
Content="按钮"
},
}
},
new WrapPanel
{
MarginRight=10,
MarginTop=10,
Width="50%",
Orientation= Orientation.Horizontal,
Children=
{
new Button
{
Content="WrapPanel的Horizontal"
},
new Button
{
Content="按钮"
},
new Button
{
Content="Margin调间距",
MarginLeft=5
},
new Button
{
Content="按钮"
},
new Button
{
Content="宽度不够"
},
new Button
{
Content="可以自动换行"
},
}
},
new Grid
{
RenderTransform=new RotateTransform(10),
Name="testGrid",
Background="#999",
Width="80%",
Height="60%",
MarginTop=120,
MarginLeft=20,
ColumnDefinitions=
{
new ColumnDefinition
{
Width="40*"
},
new ColumnDefinition
{
Width = "30*"
},
new ColumnDefinition
{
Width="200",
[nameof(ColumnDefinition.Width)]=nameof(MainModel.ColumnWidth)
},
},
RowDefinitions=
{
new RowDefinition
{
Height="30*"
},
new RowDefinition
{
Height="30*"
},
new RowDefinition
{
Height="30*"
}
},
Children=
{
new WrapPanel
{
Name="test",
Background="#a2f",
Width="100%",
Height="100%",
Children=
{
new Button
{
Content="水平浮动布局231"
},
new Button
{
Content="按钮2"
},
new Button
{
Content="按钮3"
},
new Button
{
Content="按钮4"
},
new Button
{
Content="按钮5"
},
}
},
{
new WrapPanel
{
Orientation= Orientation.Vertical,
Background="#27a",
Width="100%",
Height="100%",
Children=
{
new Button
{
Content="垂直浮动布局"
},
new Button
{
Content="按钮2"
},
new Button
{
Content="按钮3"
},
new Button
{
Content="按钮4"
},
new Button
{
Content="按钮5"
},
}
},
1,
1
},
{
new TextBlock new TextBlock
{ {
Background="#ac2", [nameof(TextBlock.Text)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name,
Width="100%", BindingMode.OneWay),
Height="100%", Name = "hmbb"
Text="Grid布局。。。"
},
2,
1
},
{
new Panel
{
Background="#b1a",
MarginLeft=0,
MarginRight=0,
Children=
{
new Button
{
Content="跨列",
Width="50%"
}
}
},
0,
2,
2
},
{
new TextBlock
{
Background="#186",
Height="100%",
Text="跨行"
},
2,
1,
1,
2
}, },
new TextBox new TextBox
{ {
MarginLeft=10, Width = 130,
Size=SizeField.Fill, Height= 60,
Text="元素变换,可以旋转,倾斜,缩放等操作", Background =Color.Gray,
Attacheds= [nameof(TextBox.Text)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name,
{ BindingMode.OneWayToSource),
{
Grid.ColumnIndex,
1
}
}
}, },
new Button new Button
{ {
Content=new SVG("res://ConsoleApp1/test.svg") Content="按钮",
[nameof(Button.Click)]=new CommandDescribe((s,e)=>
{ {
MarginLeft = 0, (DataContext as MainModel).Test1.test.test.test.test.Name = "666666";
MarginTop = 0, })
Height = 85,
Width=170,
Stretch= Stretch.Uniform,
},
Width=104,
Height=55,
MarginLeft=60,
MarginTop=120,
Commands=
{
{
nameof(Button.Click),
(s,e)=> Animation((Button)s)
}
}
}
},
},
new DockPanel
{
LastChildFill = false,
Width=200,
Height=200,
MarginRight=0,
MarginTop=50,
Background="#f00",
Children =
{
new Button
{
Content="Right",
Height="100%",
Attacheds =
{
{
DockPanel.Dock,
Dock.Right
}
}
}, },
} }
}, },
new Slider
{
Maximum = 300,
Value = 200,
MarginLeft = 252,
MarginTop = 76,
Height = 23,
Width = 219,
[nameof(Slider.Value)]=new BindingDescribe(null, nameof(MainModel.ColumnWidth),BindingMode.OneWayToSource,null,a=>new GridLength((float)(double)a))
},
} }
} }
}, },