mirror of
https://gitee.com/csharpui/CPF.git
synced 2025-08-20 00:44:27 +08:00
Merge branch 'master' into Toolkit
This commit is contained in:
commit
6631fec5e6
@ -657,6 +657,7 @@ namespace CPF.Windows
|
||||
WM_USER = 0x0400,
|
||||
WM_DISPATCH_WORK_ITEM = WM_USER,
|
||||
WM_TOUCH = 0x0240,
|
||||
WM_GESTURE = 0x0119,
|
||||
//WM_PARENTNOTIFY = 0x0210,
|
||||
WM_NCPOINTERUPDATE = 0x0241,
|
||||
WM_NCPOINTERDOWN = 0x0242,
|
||||
|
@ -74,6 +74,7 @@ namespace CPF.Windows
|
||||
}
|
||||
|
||||
WNDCLASSEX wc = new WNDCLASSEX();
|
||||
bool touchMsg;
|
||||
public WindowImpl()
|
||||
{
|
||||
if (Window == null)
|
||||
@ -89,6 +90,10 @@ namespace CPF.Windows
|
||||
{
|
||||
isLayered = true;
|
||||
}
|
||||
if ((v.Major == 6 && v.Minor < 2))
|
||||
{
|
||||
touchMsg = RegisterTouchWindow(handle, RegisterTouchFlags.TWF_NONE);
|
||||
}
|
||||
_className = "CPFWindow-" + Guid.NewGuid();
|
||||
// 初始化窗口类结构
|
||||
wc.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX));
|
||||
@ -707,60 +712,83 @@ namespace CPF.Windows
|
||||
case WindowsMessage.WM_POINTERDOWN:
|
||||
case WindowsMessage.WM_POINTERUP:
|
||||
case WindowsMessage.WM_POINTERUPDATE:
|
||||
var id = GetPointerId(wParam);
|
||||
var position = GetPointerLocation(lParam);
|
||||
position = PointToClient(position);
|
||||
//Debug.WriteLine("id:" + id + " " + position);
|
||||
POINTER_INFO pi = new POINTER_INFO();
|
||||
if (GetPointerInfo(id, ref pi))
|
||||
if (!touchMsg)
|
||||
{
|
||||
switch ((WindowsMessage)msg)
|
||||
var id = GetPointerId(wParam);
|
||||
var position = GetPointerLocation(lParam);
|
||||
position = PointToClient(position);
|
||||
//Debug.WriteLine("id:" + id + " " + position);
|
||||
POINTER_INFO pi = new POINTER_INFO();
|
||||
if (GetPointerInfo(id, ref pi))
|
||||
{
|
||||
case WindowsMessage.WM_POINTERDOWN:
|
||||
//Debug.WriteLine("down");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchDown);
|
||||
break;
|
||||
case WindowsMessage.WM_POINTERUP:
|
||||
//Debug.WriteLine("up");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchUp);
|
||||
//root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchLeave);
|
||||
break;
|
||||
case WindowsMessage.WM_POINTERUPDATE:
|
||||
//Debug.WriteLine("update");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchMove);
|
||||
break;
|
||||
switch ((WindowsMessage)msg)
|
||||
{
|
||||
case WindowsMessage.WM_POINTERDOWN:
|
||||
//Debug.WriteLine("down");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchDown);
|
||||
break;
|
||||
case WindowsMessage.WM_POINTERUP:
|
||||
//Debug.WriteLine("up");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchUp);
|
||||
//root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchLeave);
|
||||
break;
|
||||
case WindowsMessage.WM_POINTERUPDATE:
|
||||
//Debug.WriteLine("update");
|
||||
root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint { Id = id, Position = position }, root.InputManager.TouchDevice, Root), root.LayoutManager.VisibleUIElements, EventType.TouchMove);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WindowsMessage.WM_POINTERWHEEL:
|
||||
Debug.WriteLine("WM_POINTERWHEEL");
|
||||
break;
|
||||
//case WindowsMessage.WM_TOUCH:
|
||||
// {
|
||||
// var touchInputCount = wParam.ToInt32();
|
||||
// var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount];
|
||||
// if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf(typeof(TOUCHINPUT))))
|
||||
// {
|
||||
// for (int i = 0; i < touchInputCount; i++)
|
||||
// {
|
||||
// var touchInput = pTouchInputs[i];
|
||||
case WindowsMessage.WM_GESTURE:
|
||||
Debug.WriteLine("WM_GESTURE");
|
||||
break;
|
||||
case WindowsMessage.WM_TOUCH:
|
||||
if (touchMsg)
|
||||
{
|
||||
var touchInputCount = wParam.ToInt32();
|
||||
var pTouchInputs = stackalloc TOUCHINPUT[touchInputCount];
|
||||
if (GetTouchInputInfo(lParam, (uint)touchInputCount, pTouchInputs, Marshal.SizeOf(typeof(TOUCHINPUT))))
|
||||
{
|
||||
for (int i = 0; i < touchInputCount; i++)
|
||||
{
|
||||
var input = pTouchInputs[i];
|
||||
|
||||
// //Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
|
||||
// // _owner,
|
||||
// // touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_UP) ?
|
||||
// // RawPointerEventType.TouchEnd :
|
||||
// // touchInput.Flags.HasAllFlags(TouchInputFlags.TOUCHEVENTF_DOWN) ?
|
||||
// // RawPointerEventType.TouchBegin :
|
||||
// // RawPointerEventType.TouchUpdate,
|
||||
// // PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)),
|
||||
// // WindowsKeyboardDevice.Instance.Modifiers,
|
||||
// // touchInput.Id));
|
||||
// }
|
||||
// CloseTouchInputHandle(lParam);
|
||||
// return IntPtr.Zero;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
if ((input.Flags & TouchInputFlags.TOUCHEVENTF_DOWN) > 0)
|
||||
{
|
||||
Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint
|
||||
{
|
||||
Id = (int)input.Id,
|
||||
Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01))
|
||||
}, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchDown);
|
||||
|
||||
}
|
||||
else if ((input.Flags & TouchInputFlags.TOUCHEVENTF_UP) > 0)
|
||||
{
|
||||
Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint
|
||||
{
|
||||
Id = (int)input.Id,
|
||||
Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01))
|
||||
}, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchUp);
|
||||
|
||||
}
|
||||
else if ((input.Flags & TouchInputFlags.TOUCHEVENTF_MOVE) > 0)
|
||||
{
|
||||
Root.InputManager.TouchDevice.ProcessEvent(new TouchEventArgs(new TouchPoint
|
||||
{
|
||||
Id = (int)input.Id,
|
||||
Position = new Point((float)(input.X * 0.01), (float)(input.Y * 0.01))
|
||||
}, Root.InputManager.TouchDevice, Root), Root.LayoutManager.VisibleUIElements, EventType.TouchMove);
|
||||
}
|
||||
}
|
||||
CloseTouchInputHandle(lParam);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UnmanagedMethods.WindowsMessage.WM_CLOSE:
|
||||
bool? preventClosing = Closing?.Invoke();
|
||||
if (preventClosing == true)
|
||||
@ -1523,7 +1551,7 @@ namespace CPF.Windows
|
||||
}
|
||||
invalidateRect.Intersect(all);//最后失效区域为在控件区域里面的相交区域
|
||||
}
|
||||
if (!paint && (timer == null ))//&& isLayered
|
||||
if (!paint && (timer == null))//&& isLayered
|
||||
{
|
||||
paint = true;
|
||||
BeginInvoke(a =>
|
||||
@ -1692,7 +1720,6 @@ namespace CPF.Windows
|
||||
public void SetVisible(bool visible)
|
||||
{
|
||||
//var v = IsWindowVisible(handle);
|
||||
root.InputManager.TouchDevice.ClearPoints();
|
||||
if (visible)
|
||||
{
|
||||
if (windowState == WindowState.Normal)
|
||||
|
@ -212,4 +212,104 @@ namespace CPF
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 绑定附加属性
|
||||
/// </summary>
|
||||
public class AttachedDescribe : BindingDescribe
|
||||
{
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
public AttachedDescribe(object value, string sourceProperty) : base(sourceProperty)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="binding"></param>
|
||||
public AttachedDescribe(object value, string sourceProperty, BindingMode binding) : base(sourceProperty, binding)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="binding"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty, BindingMode binding) : base(source, sourceProperty, binding)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty) : base(source, sourceProperty)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="convert"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty, Func<object, object> convert) : base(source, sourceProperty, convert)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="binding"></param>
|
||||
/// <param name="convert"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty, BindingMode binding, Func<object, object> convert) : base(source, sourceProperty, binding, convert)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="binding"></param>
|
||||
/// <param name="convert"></param>
|
||||
/// <param name="convertBack"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack) : base(source, sourceProperty, binding, convert, convertBack)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 设置和绑定附加属性
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="sourceProperty"></param>
|
||||
/// <param name="binding"></param>
|
||||
/// <param name="convert"></param>
|
||||
/// <param name="convertBack"></param>
|
||||
/// <param name="SourceToTargetError"></param>
|
||||
/// <param name="TargetToSourceError"></param>
|
||||
public AttachedDescribe(object value, object source, string sourceProperty, BindingMode binding, Func<object, object> convert, Func<object, object> convertBack, Action<Binding, object, Exception> SourceToTargetError, Action<Binding, object, Exception> TargetToSourceError) : base(source, sourceProperty, binding, convert, convertBack, SourceToTargetError, TargetToSourceError)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
|
||||
public object Value { get; set; }
|
||||
}
|
||||
}
|
||||
|
130
CPF/Binding.cs
130
CPF/Binding.cs
@ -12,6 +12,7 @@ using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -236,6 +237,14 @@ namespace CPF
|
||||
internal set;
|
||||
}
|
||||
/// <summary>
|
||||
/// 链式绑定下标
|
||||
/// </summary>
|
||||
public int SourcePropertyIndex
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
} = 0;
|
||||
/// <summary>
|
||||
/// Owner被绑定的属性名
|
||||
/// </summary>
|
||||
public string TargetPropertyName
|
||||
@ -353,6 +362,7 @@ namespace CPF
|
||||
current.Push(this);
|
||||
try
|
||||
{
|
||||
|
||||
if (Source == null || !Source.IsAlive)
|
||||
{
|
||||
if (Owner.HasProperty(TargetPropertyName))
|
||||
@ -366,29 +376,22 @@ namespace CPF
|
||||
}
|
||||
return;
|
||||
}
|
||||
//CpfObject s = Source.Target as CpfObject;
|
||||
//if (s == null)
|
||||
//{
|
||||
// var p = Source.Target.GetType().GetProperty(SourcePropertyName);
|
||||
// if (p == null)
|
||||
// {
|
||||
// throw new Exception("未找到" + Source.Target + "的属性:" + SourcePropertyName);
|
||||
// }
|
||||
// value = p.FastGetValue(Source.Target);
|
||||
//}
|
||||
//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);
|
||||
/*var SourcePropertyNames = SourcePropertyName.Split('.');
|
||||
if (SourcePropertyNames.Length > 1) {
|
||||
value = Source.Target;
|
||||
for (int i = 0; i < SourcePropertyNames.Length; i++)
|
||||
{
|
||||
value = value.GetPropretyValue(SourcePropertyNames[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Source.Target.GetPropretyValue(SourcePropertyName);
|
||||
}*/
|
||||
value = GetPropertySource(SourcePropertyName, Source.Target);
|
||||
if (value != null) {
|
||||
value = value.GetPropretyValue(SourcePropertyName.Split('.').LastOrDefault());
|
||||
}
|
||||
if (Convert != null)
|
||||
{
|
||||
value = Convert(value);
|
||||
@ -453,8 +456,23 @@ namespace CPF
|
||||
{
|
||||
if (!b.SetValue(nv, SourcePropertyName))
|
||||
{
|
||||
/*var SourcePropertyNames = SourcePropertyName.Split('.');
|
||||
if (SourcePropertyNames.Length == 1)
|
||||
{
|
||||
b.SetValue(SourcePropertyName, nv);
|
||||
}*/
|
||||
/*var Target = b;
|
||||
for (int i = 0; i < SourcePropertyNames.Length-1; i++)
|
||||
{
|
||||
Target = Target.GetPropretyValue(SourcePropertyNames[i]) as CpfObject;
|
||||
}*/
|
||||
var SourcePropertyNames = SourcePropertyName.Split('.');
|
||||
var Target = GetPropertySource(SourcePropertyName, b);
|
||||
if (Target != null) {
|
||||
Target.SetValue(SourcePropertyNames.LastOrDefault(), nv);
|
||||
}
|
||||
|
||||
//b.Type.GetProperty(SourcePropertyName).FastSetValue(b, nv);
|
||||
b.SetValue(SourcePropertyName, nv);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -533,7 +551,8 @@ namespace CPF
|
||||
}
|
||||
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;
|
||||
//object value;
|
||||
@ -557,6 +576,47 @@ 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++)
|
||||
{
|
||||
var Temp_Target = Target.GetPropretyValue(SourcePropertyNames[i]) as CpfObject;
|
||||
if (Temp_Target == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Target = Temp_Target;
|
||||
}
|
||||
return Target;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"错误:{ex}");
|
||||
}
|
||||
}
|
||||
CpfObject SourceProperty = null;
|
||||
private void Target_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
//重新绑定
|
||||
if (BindingMode == BindingMode.TwoWay ||
|
||||
BindingMode == BindingMode.OneWay ||
|
||||
BindingMode == BindingMode.OneTime)
|
||||
{
|
||||
var SourcePropertyNames = SourcePropertyName.Split('.');
|
||||
var Temp_Target = GetPropertySource(SourcePropertyName, Source.Target);
|
||||
var data = (Temp_Target as CpfObject)?.GetValue(SourcePropertyNames.LastOrDefault());
|
||||
Owner.SetPropretyValue(TargetPropertyName, data);
|
||||
}
|
||||
RegisterPropertyChanged(sender as INotifyPropertyChanged);
|
||||
}
|
||||
|
||||
internal void RegisterPropertyChanged(INotifyPropertyChanged notify)
|
||||
{
|
||||
@ -564,7 +624,25 @@ namespace CPF
|
||||
//{
|
||||
// throw new Exception("错误");
|
||||
//}
|
||||
RegisterPropertyChanged(notify, PropertyChanged);
|
||||
var SourcePropertyNames = SourcePropertyName.Split('.');
|
||||
if (SourcePropertyNames.Length == 1)
|
||||
{
|
||||
RegisterPropertyChanged(notify, PropertyChanged);
|
||||
return;
|
||||
}
|
||||
var Target = Source.Target;
|
||||
RegisterPropertyChanged(Target as CpfObject, Target_PropertyChanged);
|
||||
for (int i = 0; i < SourcePropertyNames.Length - 1; i++)
|
||||
{
|
||||
var Temp_Target = Target.GetPropretyValue(SourcePropertyNames[i]) as CpfObject;
|
||||
if (Temp_Target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RegisterPropertyChanged(Temp_Target, Target_PropertyChanged);
|
||||
Target = Temp_Target;
|
||||
}
|
||||
RegisterPropertyChanged(Target as INotifyPropertyChanged, PropertyChanged);
|
||||
}
|
||||
internal void CancellationPropertyChanged(INotifyPropertyChanged notify)
|
||||
{
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -16,6 +17,7 @@ namespace CPF
|
||||
{
|
||||
PropertyName = sourceProperty;
|
||||
}
|
||||
|
||||
public BindingDescribe(string sourceProperty, BindingMode binding)
|
||||
{
|
||||
PropertyName = sourceProperty;
|
||||
@ -64,7 +66,7 @@ namespace CPF
|
||||
this.TargetToSourceError = TargetToSourceError;
|
||||
}
|
||||
|
||||
public BindingDescribe(Action<CpfObject, object> command)
|
||||
public BindingDescribe(CommandDescribe command)
|
||||
{
|
||||
Command = command;
|
||||
}
|
||||
@ -78,7 +80,7 @@ namespace CPF
|
||||
/// <summary>
|
||||
/// 简化绑定命令的命令,如果设置了该属性,则使用命令绑定
|
||||
/// </summary>
|
||||
public Action<CpfObject, object> Command { get; set; }
|
||||
public CommandDescribe Command { get; set; }
|
||||
|
||||
//public CpfObject Owner { get; internal set; }
|
||||
|
||||
@ -331,7 +333,14 @@ namespace CPF
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
//public static BindingDescribe operator *(BindingDescribe property1, string property2)
|
||||
//{
|
||||
// return null;
|
||||
//}
|
||||
//public static BindingDescribe operator *(BindingDescribe property1, BindingDescribe property2)
|
||||
//{
|
||||
// return null;
|
||||
//}
|
||||
public BindingMode BindingMode { get; set; } = BindingMode.OneWay;
|
||||
public object Source { get; set; }
|
||||
|
||||
@ -343,7 +352,7 @@ namespace CPF
|
||||
{
|
||||
return new BindingDescribe { PropertyName = sourceProperty };
|
||||
}
|
||||
public static explicit operator BindingDescribe(Action<CpfObject, object> command)
|
||||
public static implicit operator BindingDescribe(CommandDescribe command)
|
||||
{
|
||||
return new BindingDescribe { Command = command };
|
||||
}
|
||||
@ -386,5 +395,50 @@ namespace CPF
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 命令绑定
|
||||
/// </summary>
|
||||
public class CommandDescribe
|
||||
{
|
||||
public Action<CpfObject, object> Action { get; set; }
|
||||
|
||||
public string MethodName { get; set; }
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
public object Target { get; set; }
|
||||
|
||||
public Func<UIElement, UIElement> Find { get; set; }
|
||||
/// <summary>
|
||||
/// 用委托定义个命令绑定
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
public CommandDescribe(Action<CpfObject, object> command)
|
||||
{
|
||||
Action = command;
|
||||
}
|
||||
/// <summary>
|
||||
/// 定义个命令绑定
|
||||
/// </summary>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="obj"></param>
|
||||
/// <param name="ps"></param>
|
||||
public CommandDescribe(string methodName, object obj = null, params object[] ps)
|
||||
{
|
||||
MethodName = methodName;
|
||||
Parameters = ps;
|
||||
Target = obj;
|
||||
}
|
||||
/// <summary>
|
||||
/// 查找元素并绑定命令
|
||||
/// </summary>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="find"></param>
|
||||
/// <param name="ps"></param>
|
||||
public CommandDescribe(string methodName, Func<UIElement, UIElement> find, params object[] ps)
|
||||
{
|
||||
MethodName = methodName;
|
||||
Parameters = ps;
|
||||
Find = find;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
||||
using CPF.Controls;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace CPF
|
||||
{
|
||||
@ -102,6 +103,7 @@ namespace CPF
|
||||
else
|
||||
{
|
||||
//((INotifyPropertyChanged)source).PropertyChanged += b.PropertyChanged;
|
||||
|
||||
b.RegisterPropertyChanged((INotifyPropertyChanged)source);
|
||||
b.SourceToTarget();
|
||||
}
|
||||
@ -114,6 +116,7 @@ namespace CPF
|
||||
{
|
||||
b.SourceToTarget();
|
||||
}
|
||||
//Debug.WriteLine($"sourcePropertyName:{sourcePropertyName},bindingMode:{bindingMode}");
|
||||
return b;
|
||||
}
|
||||
/// <summary>
|
||||
|
@ -558,8 +558,9 @@ namespace CPF.Controls
|
||||
if (codeTextView.Text.Length >= caretIndex)
|
||||
{
|
||||
//Text = codeTextView.Text.Insert((int)caretIndex, e.Text);
|
||||
codeTextView.InsertText(caretIndex, e.Text);
|
||||
var caretIndex_old = caretIndex;
|
||||
caretIndex = caretIndex + (uint)e.Text.Length;
|
||||
codeTextView.InsertText(caretIndex_old, e.Text);
|
||||
selectionEnd = caretIndex;
|
||||
}
|
||||
else
|
||||
|
@ -11,9 +11,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace CPF.Controls
|
||||
{
|
||||
[Browsable(false)]
|
||||
public class LineNumber : Control
|
||||
{
|
||||
|
||||
|
@ -149,6 +149,25 @@ namespace CPF.Controls
|
||||
{
|
||||
base.OnOverrideMetadata(overridePropertys);
|
||||
overridePropertys.Override(nameof(Height), new UIPropertyMetadataAttribute((FloatField)"100%", UIPropertyOptions.AffectsMeasure));
|
||||
//overridePropertys.Override(nameof(DataContext), new UIPropertyMetadataAttribute(null, false));
|
||||
}
|
||||
|
||||
//protected override void OnLayoutUpdated()
|
||||
//{
|
||||
// base.OnLayoutUpdated();
|
||||
// if (Root.LayoutManager.IsVisible(this))
|
||||
// {
|
||||
// DataContext = Row.DataContext;
|
||||
// }
|
||||
//}
|
||||
|
||||
//protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||||
//{
|
||||
// if (propertyName == nameof(DataContext))
|
||||
// {
|
||||
|
||||
// }
|
||||
// base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -282,6 +282,7 @@ namespace CPF.Controls
|
||||
}
|
||||
else
|
||||
{
|
||||
textSize = new Size();
|
||||
return base.ArrangeOverride(finalSize);
|
||||
}
|
||||
}
|
||||
|
@ -860,6 +860,7 @@ namespace CPF.Controls
|
||||
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||||
if (propertyName == nameof(Visibility))
|
||||
{
|
||||
InputManager.TouchDevice.ClearPoints();
|
||||
viewImpl.SetVisible((Visibility)newValue == Visibility.Visible);
|
||||
}
|
||||
if (!onChecked && radioButtonGroupProperty != null && radiobuttons != null && radioButtonGroupProperty.TryGetValue(propertyName, out var group))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,17 +25,20 @@ namespace CPF
|
||||
static ConcurrentDictionary<Type, ObjInfo> typeCache = new ConcurrentDictionary<Type, ObjInfo>();
|
||||
static ConcurrentDictionary<Type, PropertyMetadataAttribute[]> typePropertyCache = new ConcurrentDictionary<Type, PropertyMetadataAttribute[]>();
|
||||
static ConcurrentDictionary<Type, HashSet<string>> inheritsProperties = new ConcurrentDictionary<Type, HashSet<string>>();
|
||||
static ConcurrentDictionary<Type, HashSet<string>> breakInheritsProperties = new ConcurrentDictionary<Type, HashSet<string>>();
|
||||
static ConcurrentDictionary<Type, List<MethodInfo>> propertyChangedMethods = new ConcurrentDictionary<Type, List<MethodInfo>>();
|
||||
|
||||
static KeyValuePair<Type, ObjInfo>[] saveTypeCache;
|
||||
static KeyValuePair<Type, PropertyMetadataAttribute[]>[] saveTypePropertyCache;
|
||||
static KeyValuePair<Type, HashSet<string>>[] saveInheritsProperties;
|
||||
static KeyValuePair<Type, HashSet<string>>[] saveBreakInheritsProperties;
|
||||
static KeyValuePair<Type, List<MethodInfo>>[] savePropertyChangedMethods;
|
||||
public static void SetTypeCache()
|
||||
{
|
||||
saveTypeCache = typeCache.ToArray();
|
||||
saveTypePropertyCache = typePropertyCache.ToArray();
|
||||
saveInheritsProperties = inheritsProperties.ToArray();
|
||||
saveBreakInheritsProperties = breakInheritsProperties.ToArray();
|
||||
FastReflectionExtensions.SetTypeCache();
|
||||
savePropertyChangedMethods = propertyChangedMethods.ToArray();
|
||||
}
|
||||
@ -68,6 +71,15 @@ namespace CPF
|
||||
}
|
||||
saveInheritsProperties = null;
|
||||
}
|
||||
if (saveBreakInheritsProperties != null)
|
||||
{
|
||||
breakInheritsProperties.Clear();
|
||||
foreach (var item in saveBreakInheritsProperties)
|
||||
{
|
||||
breakInheritsProperties.TryAdd(item.Key, item.Value);
|
||||
}
|
||||
saveBreakInheritsProperties = null;
|
||||
}
|
||||
if (savePropertyChangedMethods != null)
|
||||
{
|
||||
propertyChangedMethods.Clear();
|
||||
@ -88,9 +100,13 @@ namespace CPF
|
||||
|
||||
internal HybridDictionary<string, object> attachedValues;
|
||||
/// <summary>
|
||||
/// 继承属性的特性
|
||||
/// 继承属性,不同继承类型分支下来的属性名可能相同但是属性ID不同,只能保存属性名
|
||||
/// </summary>
|
||||
internal HashSet<string> inheritsPropertyName;
|
||||
/// <summary>
|
||||
/// 终止继承属性,不同继承类型分支下来的属性名可能相同但是属性ID不同,只能保存属性名
|
||||
/// </summary>
|
||||
internal HashSet<string> breakInheritsPropertyName;
|
||||
|
||||
AttachedProperties attached;
|
||||
/// <summary>
|
||||
@ -178,7 +194,21 @@ namespace CPF
|
||||
{
|
||||
if (value.Command != null)
|
||||
{
|
||||
Commands.Add(propertyName, value.Command);
|
||||
if (value.Command.Action != null)
|
||||
{
|
||||
Commands.Add(propertyName, value.Command.Action);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(value.Command.MethodName))
|
||||
{
|
||||
if (value.Command.Find != null)
|
||||
{
|
||||
Commands.Add(propertyName, value.Command.MethodName, value.Command.Find, value.Command.Parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
Commands.Add(propertyName, value.Command.MethodName, value.Command.Target, value.Command.Parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -217,8 +247,20 @@ namespace CPF
|
||||
var type = attached.GetType();
|
||||
try
|
||||
{
|
||||
var p = typeof(OptionalParameter<>).MakeGenericType(type.GetGenericArguments()[0]);
|
||||
attached.Method.FastInvoke(attached.Target, this, Activator.CreateInstance(p, value));
|
||||
if (value is AttachedDescribe describe)
|
||||
{
|
||||
var p = typeof(OptionalParameter<>).MakeGenericType(type.GetGenericArguments()[0]);
|
||||
attached.Method.FastInvoke(attached.Target, this, Activator.CreateInstance(p, describe.Value));
|
||||
var targetType = attached.Target.GetType();
|
||||
var field = targetType.GetField("propertyName");
|
||||
var name = field.FastGetValue(attached.Target).ToString();
|
||||
AttachedNotify.Bindings.Add(name, describe.PropertyName, describe.Source, describe.BindingMode, describe.Convert, describe.ConvertBack, describe.SourceToTargetError, describe.TargetToSourceError);
|
||||
}
|
||||
else
|
||||
{
|
||||
var p = typeof(OptionalParameter<>).MakeGenericType(type.GetGenericArguments()[0]);
|
||||
attached.Method.FastInvoke(attached.Target, this, Activator.CreateInstance(p, value));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -327,18 +369,31 @@ namespace CPF
|
||||
typePropertyCache.TryAdd(type, propertyList.ToArray());
|
||||
|
||||
var l = new HashSet<string>();
|
||||
var b = new HashSet<string>();
|
||||
foreach (var item in objInfo)
|
||||
{
|
||||
if (item.Value is UIPropertyMetadataAttribute attribute && attribute.Inherits)
|
||||
if (item.Value is UIPropertyMetadataAttribute attribute)
|
||||
{
|
||||
l.Add(attribute.PropertyName);
|
||||
if (attribute.Inherits)
|
||||
{
|
||||
l.Add(attribute.PropertyName);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.Add(attribute.PropertyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (l.Count == 0)
|
||||
{
|
||||
l = null;
|
||||
}
|
||||
if (b.Count == 0)
|
||||
{
|
||||
b = null;
|
||||
}
|
||||
inheritsProperties.TryAdd(type, l);
|
||||
breakInheritsProperties.TryAdd(type, b);
|
||||
|
||||
//Type tt = typeof(PropertyChangedAttribute);
|
||||
//var ms = type.FindMembers(MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, (a, b) => a.CustomAttributes.Any(c => c.AttributeType == tt), null);
|
||||
@ -444,6 +499,8 @@ namespace CPF
|
||||
//valueIndexs = new ByteArray((byte)objInfo.Count);
|
||||
valueIndexs = new byte[objInfo.Count];
|
||||
inheritsPropertyName = inheritsProperties[type];
|
||||
breakInheritsPropertyName = breakInheritsProperties[type];
|
||||
|
||||
if (objInfo.Computed != null)
|
||||
{
|
||||
foreach (var item in objInfo.Computed)
|
||||
|
@ -213,7 +213,6 @@ namespace CPF.Design
|
||||
|
||||
public void SetVisible(bool visible)
|
||||
{
|
||||
root.InputManager.TouchDevice.ClearPoints();
|
||||
root.LayoutManager.ExecuteLayoutPass();
|
||||
root.Invalidate();
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ namespace CPF
|
||||
{
|
||||
if (item.IsDisposed)
|
||||
{
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
var rect = GetRect(item.Parent, item.GetContentBounds(), item);
|
||||
rect.Intersect(new Rect(new Point(), item.ActualSize));
|
||||
|
53
CPF/Obx.cs
Normal file
53
CPF/Obx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1372,29 +1372,41 @@ namespace CPF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 继承属性需要一级级传递,直到没有元素或者取消继承为止
|
||||
/// </summary>
|
||||
/// <param name="element"></param>
|
||||
/// <param name="propertyName"></param>
|
||||
/// <param name="oldValue"></param>
|
||||
/// <param name="newValue"></param>
|
||||
void Inherits(UIElement element, string propertyName, object oldValue, object newValue)
|
||||
{
|
||||
if (!element.HasLocalOrStyleValue(propertyName, out var p))
|
||||
{
|
||||
element.inheritsSet = true;
|
||||
//var p = element.GetPropertyMetadata(propertyName);
|
||||
if (p != null)
|
||||
|
||||
var ui = p as UIPropertyMetadataAttribute;
|
||||
if (ui != null && ui.Inherits)
|
||||
{
|
||||
if (p is UIPropertyMetadataAttribute ui && ui.Inherits)
|
||||
{
|
||||
element.inheritsValues.Remove(propertyName);
|
||||
element.inheritsValues.Add(propertyName, new InheritsValue { Value = newValue, ValueForm = ValueFrom.Property });
|
||||
}
|
||||
element.inheritsSet = true;
|
||||
element.inheritsValues.Remove(propertyName);
|
||||
element.inheritsValues.Add(propertyName, new InheritsValue { Value = newValue, ValueForm = ValueFrom.Property });
|
||||
element.OnPropertyChanged(propertyName, oldValue, newValue, p);
|
||||
element.inheritsSet = false;
|
||||
for (int i = 0; i < element.Children.Count; i++)
|
||||
{
|
||||
Inherits(element.children[i], propertyName, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
else if (ui == null)
|
||||
{
|
||||
for (int i = 0; i < element.Children.Count; i++)
|
||||
{
|
||||
Inherits(element.children[i], propertyName, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
element.inheritsSet = false;
|
||||
//if (propertyName != nameof(DataContext) || !element.HasLocalOrStyleValue(propertyName, out p))
|
||||
//{
|
||||
for (int i = 0; i < element.Children.Count; i++)
|
||||
{
|
||||
Inherits(element.children[i], propertyName, oldValue, newValue);
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
@ -2480,6 +2492,9 @@ namespace CPF
|
||||
viewRenderRect = true;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否需要更新渲染区域
|
||||
/// </summary>
|
||||
[NotCpfProperty]
|
||||
internal bool viewRenderRect { get { return GetFlag(CoreFlags.viewRenderRect); } set { SetFlag(CoreFlags.viewRenderRect, value); } }
|
||||
//protected virtual void ArrangeCore(in Rect finalRect)
|
||||
@ -3441,7 +3456,7 @@ namespace CPF
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (p.HasLocalOrStyleValue(item, out _))
|
||||
else if (p.HasLocalOrStyleValue(item, out var pa))
|
||||
{
|
||||
var value = p.GetValue(item);
|
||||
var old = GetValue(item);
|
||||
@ -3457,6 +3472,10 @@ namespace CPF
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p.breakInheritsPropertyName != null && p.breakInheritsPropertyName.Contains(item))
|
||||
{
|
||||
break;
|
||||
}
|
||||
p = p.Parent;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
#if Net4||Net2
|
||||
namespace System
|
||||
{
|
||||
/// <summary>
|
||||
/// 值元组
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
[Serializable]
|
||||
public struct ValueTuple<T1, T2>
|
||||
{
|
||||
public ValueTuple(T1 item1, T2 item2)
|
||||
{
|
||||
Item1 = item1;
|
||||
Item2 = item2;
|
||||
}
|
||||
|
||||
public T1 Item1;
|
||||
|
||||
public T2 Item2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.0;net40;net5;net6</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp3.0;net40;net5;net6;net8</TargetFrameworks>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
<OutputType>WinExe</OutputType>
|
||||
@ -110,6 +110,7 @@
|
||||
<PropertyGroup>
|
||||
<DefineConstants Condition="'$(TargetFramework)'=='net40'">Net4</DefineConstants>
|
||||
<AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects>
|
||||
<Nullable>disable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.0|AnyCPU'">
|
||||
<Optimize>false</Optimize>
|
||||
|
@ -3,11 +3,81 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using CPF.Controls;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace ConsoleApp1
|
||||
{
|
||||
public class data : CpfObject
|
||||
{
|
||||
public data test {
|
||||
get
|
||||
{
|
||||
return (data)GetValue();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
}
|
||||
}
|
||||
public data()
|
||||
{
|
||||
test = this;
|
||||
}
|
||||
[PropertyMetadata(null)]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)GetValue();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class dataa : CpfObject
|
||||
{
|
||||
public data test
|
||||
{
|
||||
get
|
||||
{
|
||||
return (data)GetValue();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
}
|
||||
}
|
||||
public dataa()
|
||||
{
|
||||
// test = new data();
|
||||
}
|
||||
[PropertyMetadata(null)]
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)GetValue();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
class MainModel : CpfObject
|
||||
{
|
||||
public dataa Test1 {
|
||||
get
|
||||
{
|
||||
return (dataa)GetValue();
|
||||
}
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
}
|
||||
}
|
||||
[PropertyMetadata("默认值")]
|
||||
public string Test
|
||||
{
|
||||
@ -28,6 +98,7 @@ namespace ConsoleApp1
|
||||
|
||||
public MainModel()
|
||||
{
|
||||
Test1 = new dataa();
|
||||
Items = new Collection<(string, string)>();
|
||||
TestItems = new Collection<(string, int)>();
|
||||
|
||||
|
@ -188,6 +188,7 @@ namespace ConsoleApp1
|
||||
{
|
||||
MarginTop = 0,
|
||||
Content = "点击生成pdf",
|
||||
[nameof(Button.Content)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name),
|
||||
Commands =
|
||||
{
|
||||
{
|
||||
@ -235,7 +236,7 @@ namespace ConsoleApp1
|
||||
Content="另外一个演示窗体😍",
|
||||
MarginTop=20,
|
||||
MarginLeft=20,
|
||||
[nameof(Button.Click)]=(BindingDescribe)((s,e)=>
|
||||
[nameof(Button.Click)]=new CommandDescribe((s,e)=>
|
||||
{
|
||||
var w = new Window1();
|
||||
w.DataContext = model;
|
||||
@ -1386,7 +1387,8 @@ namespace ConsoleApp1
|
||||
MarginTop = 76,
|
||||
Height = 23,
|
||||
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
|
||||
{
|
||||
Header="布局",
|
||||
Header="多级绑定",
|
||||
Content=new Panel
|
||||
{
|
||||
Name = "布局",
|
||||
Name = "多级绑定",
|
||||
PresenterFor = this,
|
||||
Width="100%",
|
||||
Height="100%",
|
||||
@ -2435,306 +2437,54 @@ new TabItemTemplate{
|
||||
Orientation= Orientation.Vertical,
|
||||
Children=
|
||||
{
|
||||
new Button
|
||||
|
||||
new TextBlock
|
||||
{
|
||||
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
|
||||
{
|
||||
Background="#ac2",
|
||||
Width="100%",
|
||||
Height="100%",
|
||||
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
|
||||
[nameof(TextBlock.Text)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name,
|
||||
BindingMode.OneWay),
|
||||
Name = "hmbb"
|
||||
},
|
||||
new TextBox
|
||||
{
|
||||
MarginLeft=10,
|
||||
Size=SizeField.Fill,
|
||||
Text="元素变换,可以旋转,倾斜,缩放等操作",
|
||||
Attacheds=
|
||||
{
|
||||
{
|
||||
Grid.ColumnIndex,
|
||||
1
|
||||
}
|
||||
}
|
||||
Width = 130,
|
||||
Height= 60,
|
||||
Background =Color.Gray,
|
||||
[nameof(TextBox.Text)]= new Obx<MainModel>(a => a.Test1.test.test.test.test.Name,
|
||||
BindingMode.OneWayToSource),
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content=new SVG("res://ConsoleApp1/test.svg")
|
||||
Content="创建对象",
|
||||
[nameof(Button.Click)]=new CommandDescribe((s,e)=>
|
||||
{
|
||||
MarginLeft = 0,
|
||||
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 =
|
||||
{
|
||||
data a = new data();
|
||||
a.test.test.test.Name = "666666";
|
||||
(DataContext as MainModel).Test1.test = a;
|
||||
})
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content="Right",
|
||||
Height="100%",
|
||||
Attacheds =
|
||||
Content="删除对象",
|
||||
[nameof(Button.Click)]=new CommandDescribe((s,e)=>
|
||||
{
|
||||
{
|
||||
DockPanel.Dock,
|
||||
Dock.Right
|
||||
}
|
||||
}
|
||||
data a = new data();
|
||||
a.test.test.Name = "666666";
|
||||
(DataContext as MainModel).Test1.test.test = null;
|
||||
})
|
||||
},
|
||||
new Button
|
||||
{
|
||||
Content="添加对象",
|
||||
[nameof(Button.Click)]=new CommandDescribe((s,e)=>
|
||||
{
|
||||
data a = new data();
|
||||
a.test.test.Name = "666666";
|
||||
(DataContext as MainModel).Test1.test.test = a;
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
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))
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
|
BIN
Other/yunchaobi.gif
Normal file
BIN
Other/yunchaobi.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 MiB |
25
README.md
25
README.md
@ -3,12 +3,12 @@
|
||||
#### 介绍
|
||||
C#跨平台UI框架
|
||||
|
||||
提供NETStandard2.0和net4的库,通过Netcore可以跨平台,支持Windows、Mac、Linux,Net4的可以支持XP。各个平台运行效果一致,不依赖系统控件。
|
||||
支持窗体,控件任意透明,支持异形窗体,支持SVG图标显示。
|
||||
支持动画,数据绑定,Mvvm模式,CSS等,简化依赖属性,数据绑定的写法,提供数据上下文和命令上下文来绑定,直接用CSS和C#代码描述。
|
||||
提供设计器生成C#代码和开发者工具查看和调试元素
|
||||
和WPF一样的理念,任何控件都可以任意设计模板来实现各种效果
|
||||
除了使用平台相关API之外,基本可以实现一次编写,到处运行
|
||||
提供NETStandard2.0和net4的库,通过Netcore可以跨平台,支持Windows、Mac、Linux,Net4的可以支持XP。各个平台运行效果一致,不依赖系统控件。<br/>
|
||||
支持窗体,控件任意透明,支持异形窗体,支持SVG图标显示。<br/>
|
||||
支持动画,数据绑定,Mvvm模式,CSS等,简化依赖属性,数据绑定的写法,提供数据上下文和命令上下文来绑定,直接用CSS和C#代码描述。<br/>
|
||||
提供设计器生成C#代码和开发者工具查看和调试元素<br/>
|
||||
和WPF一样的理念,任何控件都可以任意设计模板来实现各种效果<br/>
|
||||
除了使用平台相关API之外,基本可以实现一次编写,到处运行<br/>
|
||||
全面支持国产化,支持国产Linux + 龙芯、飞腾、兆芯、海光等CPU平台
|
||||
|
||||

|
||||
@ -17,7 +17,9 @@ C#跨平台UI框架
|
||||
|
||||

|
||||
|
||||
Apache License 2.0
|
||||

|
||||
|
||||
**Apache License 2.0**
|
||||
|
||||
#### 软件架构
|
||||
软件架构说明
|
||||
@ -29,6 +31,14 @@ CPF为主要框架,CPF.Skia为用skia做图形适配,CPF.Windows、CPF.Linux
|
||||
|
||||
直接克隆/下载就可以编译,直接启动ConsoleApp1看运行效果
|
||||
|
||||
CPF使用文档 http://cpf.cskin.net/Course/#/
|
||||
|
||||
#### 扩展库
|
||||
|
||||
https://gitee.com/csharpui/cpf.cef 使用CPF对cef的封装,跨平台浏览器控件
|
||||
|
||||
https://gitee.com/csharpui/cpf.vlc 使用CPF对vlc的封装,跨平台视频播放控件
|
||||
|
||||
#### 关于设计器
|
||||
|
||||
设计器不开源,设计器是需要另外收费的,免费模式可以刷新和预览,不能拖拽和审查元素,可以免费试用VIP一个月
|
||||
@ -51,3 +61,4 @@ CPF为主要框架,CPF.Skia为用skia做图形适配,CPF.Windows、CPF.Linux
|
||||
3. 提交代码
|
||||
4. 新建 Pull Request
|
||||
|
||||
QQ群:894952004
|
||||
|
Loading…
Reference in New Issue
Block a user