4256 lines
150 KiB
C#
4256 lines
150 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using CPF;
|
||
using CPF.Input;
|
||
using CPF.Styling;
|
||
using CPF.Shapes;
|
||
using CPF.Reflection;
|
||
using System.Linq;
|
||
using System.ComponentModel;
|
||
using System.ComponentModel.Design;
|
||
using System.ComponentModel.Design.Serialization;
|
||
using System.Runtime.CompilerServices;
|
||
using CPF.Controls;
|
||
using CPF.Drawing;
|
||
using System.Runtime.InteropServices;
|
||
using System.Collections;
|
||
using System.Diagnostics;
|
||
using System.Threading;
|
||
|
||
namespace CPF
|
||
{
|
||
/// <summary>
|
||
/// 提供UI相关的特性,图像,鼠标事件,触摸事件,布局,拖拽事件
|
||
/// </summary>
|
||
//[ContentProperty("Children")]
|
||
//[Designer(typeof(Design.DocumentDesigner), typeof(IRootDesigner))]
|
||
//[Designer(typeof(Design.DocumentDesigner), typeof(IDesigner))]
|
||
[DesignerCategory("Component")]
|
||
//[DesignerSerializer(typeof(),typeof(System.ComponentModel.Design.Serialization.CodeDomSerializer))]
|
||
[ToolboxItem(false)]
|
||
public class UIElement : Visual, IComponent//, IEnumerable<UIElement>//, INamed//, IInputElement
|
||
{
|
||
//internal bool needSortZIndex = false;
|
||
//List<UIElement> visibleElements;
|
||
internal UIElement mouseOverChild = null;
|
||
internal UIElement dragOverChild = null;
|
||
Size desiredSize;
|
||
Rect previousRenderRect;
|
||
//Size previousDesiredSize;
|
||
//bool isMeasureValid = true;
|
||
internal Rect? _previousArrange;
|
||
internal Size? _previousMeasure;
|
||
Rect contentBounds;
|
||
HybridDictionary<INotifyPropertyChanged, HashSet<UIPropertyMetadataAttribute>> notifyList;
|
||
Effects.Effect effect;
|
||
static Popup tooltip;
|
||
static Threading.DispatcherTimer timer;
|
||
internal Delegate afterStyle;
|
||
static Popup ToolTipHost
|
||
{
|
||
get
|
||
{
|
||
if (tooltip == null)
|
||
{
|
||
tooltip = new Popup() { Name = "tooltip", CanActivate = false, Background = Color.Transparent };
|
||
}
|
||
return tooltip;
|
||
}
|
||
}
|
||
|
||
static void ShowTip(View root, UIElement toolTipElement)
|
||
{
|
||
if (timer == null)
|
||
{
|
||
timer = new Threading.DispatcherTimer();
|
||
timer.Interval = TimeSpan.FromSeconds(.3);
|
||
timer.Tick += Timer_Tick;
|
||
}
|
||
UIElement.toolTipRoot = root;
|
||
ToolTipUIElement = toolTipElement;
|
||
timer.Start();
|
||
}
|
||
static View toolTipRoot;
|
||
static UIElement toolTipUIElement;
|
||
static UIElement ToolTipUIElement
|
||
{
|
||
get { return toolTipUIElement; }
|
||
set
|
||
{
|
||
if (toolTipUIElement != value)
|
||
{
|
||
if (toolTipUIElement != null)
|
||
{
|
||
ToolTipHost.Children.Remove(toolTipUIElement);
|
||
if (tooltip.Visibility == Visibility.Visible)
|
||
{
|
||
tooltip.Visibility = Visibility.Collapsed;
|
||
}
|
||
}
|
||
}
|
||
toolTipUIElement = value;
|
||
}
|
||
}
|
||
private static void Timer_Tick(object sender, EventArgs e)
|
||
{
|
||
timer.Stop();
|
||
if (toolTipRoot == null || !toolTipUIElement)
|
||
{
|
||
return;
|
||
}
|
||
//var p = MouseDevice.Location;
|
||
//ToolTipHost.MarginLeft = p.X / toolTipRoot.LayoutScaling + 10;
|
||
//ToolTipHost.MarginTop = p.Y / toolTipRoot.LayoutScaling + 10;
|
||
//ToolTipHost.Position = new PixelPoint(p.X + 10, p.Y + 10);
|
||
ToolTipHost.MarginLeft = 10;
|
||
ToolTipHost.MarginTop = 10;
|
||
ToolTipHost.Placement = PlacementMode.Mouse;
|
||
ToolTipHost.PlacementTarget = toolTipRoot;
|
||
ToolTipHost.LoadStyle(toolTipRoot);
|
||
ToolTipHost.Children.Add(toolTipUIElement);
|
||
ToolTipHost.Visibility = Visibility.Visible;
|
||
UIElement.toolTipRoot = null;
|
||
//toolTipUIElement = null;
|
||
}
|
||
|
||
internal Classes classes;
|
||
internal long lastMouseDownTime;
|
||
Point lastMouseDown;
|
||
internal void RaiseDeviceEvent(EventArgs e, EventType eventName)
|
||
{
|
||
if (Root == null)
|
||
{
|
||
return;
|
||
}
|
||
switch (eventName)
|
||
{
|
||
case EventType.MouseMove:
|
||
OnMouseMove((MouseEventArgs)e);
|
||
break;
|
||
case EventType.PreviewMouseDown:
|
||
OnPreviewMouseDown((MouseButtonEventArgs)e);
|
||
break;
|
||
case EventType.PreviewMouseUp:
|
||
OnPreviewMouseUp((MouseButtonEventArgs)e);
|
||
break;
|
||
case EventType.MouseDown:
|
||
{
|
||
OnMouseDown((MouseButtonEventArgs)e);
|
||
var p = ((MouseButtonEventArgs)e).Location;
|
||
if (lastMouseDownTime != 0)
|
||
{
|
||
var time = DateTime.FromBinary(lastMouseDownTime);
|
||
var now = DateTime.FromBinary(((MouseButtonEventArgs)e).timestamp);
|
||
if (Platform.Application.GetRuntimePlatform().DoubleClickTime > now - time && Math.Abs(p.X - lastMouseDown.X) < 2 && Math.Abs(p.Y - lastMouseDown.Y) < 2)
|
||
{
|
||
OnDoubleClick((RoutedEventArgs)e);
|
||
return;
|
||
}
|
||
}
|
||
lastMouseDown = p;
|
||
lastMouseDownTime = ((MouseButtonEventArgs)e).timestamp;
|
||
break;
|
||
}
|
||
|
||
case EventType.MouseUp:
|
||
OnMouseUp((MouseButtonEventArgs)e);
|
||
break;
|
||
case EventType.MouseEnter:
|
||
OnMouseEnter((MouseEventArgs)e);
|
||
break;
|
||
case EventType.MouseLeave:
|
||
OnMouseLeave((MouseEventArgs)e);
|
||
break;
|
||
case EventType.MouseWheel:
|
||
OnMouseWheel((MouseWheelEventArgs)e);
|
||
break;
|
||
case EventType.KeyDown:
|
||
OnKeyDown((KeyEventArgs)e);
|
||
break;
|
||
case EventType.KeyUp:
|
||
OnKeyUp((KeyEventArgs)e);
|
||
break;
|
||
case EventType.TextInput:
|
||
OnTextInput((TextInputEventArgs)e);
|
||
break;
|
||
case EventType.DragOver:
|
||
OnDragOver((DragEventArgs)e);
|
||
break;
|
||
case EventType.DragEnter:
|
||
var dea = e as DragEventArgs;
|
||
OnDragEnter(dea);
|
||
break;
|
||
case EventType.DragLeave:
|
||
OnDragLeave(e);
|
||
break;
|
||
case EventType.Drop:
|
||
OnDrop((DragEventArgs)e);
|
||
break;
|
||
case EventType.TouchDown:
|
||
OnTouchDown((TouchEventArgs)e);
|
||
break;
|
||
case EventType.TouchUp:
|
||
OnTouchUp((TouchEventArgs)e);
|
||
break;
|
||
//case EventType.TouchEnter:
|
||
// OnTouchEnter((TouchEventArgs)e);
|
||
// break;
|
||
//case EventType.TouchLeave:
|
||
// OnTouchLeave((TouchEventArgs)e);
|
||
//break;
|
||
case EventType.TouchMove:
|
||
OnTouchMove((TouchEventArgs)e);
|
||
break;
|
||
}
|
||
}
|
||
public UIElement()
|
||
{
|
||
loadStyle = true;
|
||
IsMeasureValid = true;
|
||
if (inheritsPropertyName != null)
|
||
{
|
||
inheritsValues = new Dictionary<string, InheritsValue>();
|
||
}
|
||
}
|
||
Dictionary<string, InheritsValue> inheritsValues;
|
||
|
||
List<UIElement> presenters;
|
||
/// <summary>
|
||
/// 被标记了的元素
|
||
/// </summary>
|
||
[NotCpfProperty, Browsable(false)]
|
||
public IEnumerable<UIElement> Presenters
|
||
{
|
||
get { return presenters; }
|
||
}
|
||
|
||
UIElement presenterFor;
|
||
/// <summary>
|
||
/// 用作模板中的特殊元素的标记,强引用,不使用了的元素只Remove是不行的,需要设置PresenterFor=null或者调用Dispose
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
public UIElement PresenterFor
|
||
{
|
||
get { return presenterFor; }
|
||
set
|
||
{
|
||
if (presenterFor != value)
|
||
{
|
||
if (value != null)
|
||
{
|
||
if (value.presenters == null)
|
||
{
|
||
value.presenters = new List<UIElement>();
|
||
}
|
||
value.presenters.Add(this);
|
||
}
|
||
if (presenterFor != null && presenterFor.presenters != null)
|
||
{
|
||
presenterFor.presenters.Remove(this);
|
||
}
|
||
presenterFor = value;
|
||
}
|
||
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 查找标记了的特殊元素
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IEnumerable<T> FindPresenter<T>() where T : UIElement
|
||
{
|
||
//return Find<UIElement>().Where(a => a.PresenterFor == this);
|
||
if (presenters == null)
|
||
{
|
||
yield break;
|
||
}
|
||
foreach (var item in presenters)
|
||
{
|
||
if (item is T t)
|
||
{
|
||
yield return t;
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 查找标记了的特殊元素,绑定的时候使用
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="func"></param>
|
||
/// <returns></returns>
|
||
public Func<UIElement, UIElement> FindPresenter<T>(Func<T, bool> func) where T : UIElement
|
||
{
|
||
Func<UIElement, UIElement> func1 = a =>
|
||
{
|
||
return FindPresenter<T>().FirstOrDefault(func);
|
||
};
|
||
return func1;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找标记了的特殊元素
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IEnumerable<UIElement> FindPresenter()
|
||
{
|
||
return FindPresenter<UIElement>();
|
||
}
|
||
/// <summary>
|
||
/// 通过Name查找标记了的特殊元素
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="name"></param>
|
||
/// <returns></returns>
|
||
public T FindPresenterByName<T>(string name) where T : UIElement
|
||
{
|
||
return FindPresenter<T>().FirstOrDefault(a => a.Name == name);
|
||
}
|
||
/// <summary>
|
||
/// 通过Name查找标记了的特殊元素。绑定的时候用
|
||
/// </summary>
|
||
/// <param name="name"></param>
|
||
/// <returns></returns>
|
||
public Func<UIElement, UIElement> FindPresenterByName(string name)
|
||
{
|
||
Func<UIElement, UIElement> func1 = b =>
|
||
{
|
||
return FindPresenter<UIElement>().FirstOrDefault(a => a.Name == name);
|
||
};
|
||
return func1;
|
||
}
|
||
|
||
///// <summary>
|
||
///// 添加子元素 Children.Add(element);
|
||
///// </summary>
|
||
///// <param name="element"></param>
|
||
//public void Add(UIElement element)
|
||
//{
|
||
// Children.Add(element);
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 位图特效
|
||
/// </summary>
|
||
[Description("位图特效")]
|
||
[UIPropertyMetadata(null, UIPropertyOptions.AffectsRender)]
|
||
[Browsable(false)]
|
||
public Effects.Effect Effect
|
||
{
|
||
get { return GetValue<Effects.Effect>(); }
|
||
set { SetValue(value); }
|
||
}
|
||
/// <summary>
|
||
/// 获取或设置在用户界面 (UI) 中为此元素显示的工具提示对象
|
||
/// </summary>
|
||
[Description("获取或设置在用户界面 (UI) 中为此元素显示的工具提示对象"), TypeConverter(typeof(StringConverter))]
|
||
public object ToolTip
|
||
{
|
||
get { return GetValue(40); }
|
||
set { SetValue(value, 40); }
|
||
}
|
||
UIElement toolTipElement;
|
||
//public UIElement(IViewImpl host) : this()
|
||
//{
|
||
// this.Host = host;
|
||
// IsRoot = true;
|
||
//}
|
||
/// <summary>
|
||
/// 元素名称
|
||
/// </summary>
|
||
[Category("设计")]
|
||
[Description("元素名称")]
|
||
public virtual string Name
|
||
{
|
||
get { return GetValue<string>(34); }
|
||
set { SetValue(value, 34); }
|
||
}
|
||
/// <summary>
|
||
/// 键盘焦点
|
||
/// </summary>
|
||
[UIPropertyMetadata(false, UIPropertyOptions.AffectsRender)]
|
||
[Description("键盘焦点")]
|
||
public bool IsKeyboardFocused
|
||
{
|
||
get { return (bool)GetValue(22); }
|
||
private set { SetValue(value, 22); }
|
||
}
|
||
/// <summary>
|
||
/// 获取一个值,该值指示键盘焦点是否位于元素或其可视化树子元素内的任意位置
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("获取一个值,该值指示键盘焦点是否位于元素或其可视化树子元素内的任意位置")]
|
||
public bool IsKeyboardFocusWithin
|
||
{
|
||
get { return (bool)GetValue(21); }
|
||
private set { SetValue(value, 21); }
|
||
}
|
||
/// <summary>
|
||
/// 获取焦点的导航方式
|
||
/// </summary>
|
||
[Description("获取焦点的导航方式")]
|
||
[PropertyMetadata(null)]
|
||
public NavigationMethod? FocusMethod
|
||
{
|
||
get { return (NavigationMethod?)GetValue(13); }
|
||
private set { SetValue(value, 13); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否可以获取焦点
|
||
/// </summary>
|
||
[Description("是否可以获取焦点")]
|
||
[PropertyMetadata(false)]
|
||
public bool Focusable
|
||
{
|
||
get { return GetValue<bool>(14); }
|
||
set { SetValue(value, 14); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 与控件关联的用户自定义数据
|
||
/// </summary>
|
||
[Description("与控件关联的用户自定义数据"), DefaultValue(null), TypeConverter(typeof(StringConverter))]
|
||
public object Tag
|
||
{
|
||
get { return GetValue(39); }
|
||
set { SetValue(value, 39); }
|
||
}
|
||
/// <summary>
|
||
/// 是否有逻辑焦点
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("是否有逻辑焦点")]
|
||
public bool IsFocused
|
||
{
|
||
get { return GetValue<bool>(19); }
|
||
private set { SetValue(value, 19); }
|
||
}
|
||
/// <summary>
|
||
/// tab键切换元素焦点时候的顺序
|
||
/// </summary>
|
||
[PropertyMetadata(0)]
|
||
[Description("tab键切换元素焦点时候的顺序")]
|
||
public int TabIndex
|
||
{
|
||
get { return GetValue<int>(38); }
|
||
set { SetValue(value, 38); }
|
||
}
|
||
/// <summary>
|
||
/// 按tab键切换焦点显示的聚焦框填充
|
||
/// </summary>
|
||
[Description("按tab键切换焦点显示的聚焦框填充")]
|
||
[PropertyMetadata(typeof(ViewFill), "#000")]
|
||
public ViewFill FocusFrameFill
|
||
{
|
||
get { return GetValue<ViewFill>(10); }
|
||
set { SetValue(value, 10); }
|
||
}
|
||
/// <summary>
|
||
/// 按tab键切换焦点显示的聚焦框
|
||
/// </summary>
|
||
[Description("按tab键切换焦点显示的聚焦框")]
|
||
[PropertyMetadata(typeof(Stroke), "1,Dash")]
|
||
public Stroke FocusFrameStroke
|
||
{
|
||
get { return GetValue<Stroke>(12); }
|
||
set { SetValue(value, 12); }
|
||
}
|
||
/// <summary>
|
||
/// 聚焦框到元素边缘距离
|
||
/// </summary>
|
||
[UIPropertyMetadata(typeof(Thickness), "3", UIPropertyOptions.AffectsRender), Description("聚焦框到元素边缘距离")]
|
||
public Thickness FocusFramePadding
|
||
{
|
||
get { return GetValue<Thickness>(11); }
|
||
set { SetValue(value, 11); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 图形抗锯齿
|
||
/// </summary>
|
||
[Description("图形抗锯齿")]
|
||
[UIPropertyMetadata(false, UIPropertyOptions.Inherits | UIPropertyOptions.AffectsRender)]
|
||
public bool IsAntiAlias
|
||
{
|
||
get { return GetValue<bool>(16); }
|
||
set { SetValue(value, 16); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 该值指示此元素是否捕获了鼠标
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("该值指示此元素是否捕获了鼠标")]
|
||
public bool IsMouseCaptured
|
||
{
|
||
get { return GetValue<bool>(23); }
|
||
private set { SetValue(value, 23); }
|
||
}
|
||
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "0", UIPropertyOptions.AffectsMeasure)]
|
||
public FloatField MinWidth
|
||
{
|
||
get { return GetValue<FloatField>(33); }
|
||
set { SetValue(value, 33); }
|
||
}
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "0", UIPropertyOptions.AffectsMeasure)]
|
||
public FloatField MinHeight
|
||
{
|
||
get { return GetValue<FloatField>(32); }
|
||
set { SetValue(value, 32); }
|
||
}
|
||
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public FloatField MaxWidth
|
||
{
|
||
get { return GetValue<FloatField>(31); }
|
||
set { SetValue(value, 31); }
|
||
}
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public FloatField MaxHeight
|
||
{
|
||
get { return GetValue<FloatField>(30); }
|
||
set { SetValue(value, 30); }
|
||
}
|
||
/// <summary>
|
||
/// 是否可以通过鼠标点击到
|
||
/// </summary>
|
||
[Description("是否可以通过鼠标点击到")]
|
||
[PropertyMetadata(true)]
|
||
public bool IsHitTestVisible
|
||
{
|
||
get { return GetValue<bool>(20); }
|
||
set { SetValue(value, 20); }
|
||
}
|
||
/// <summary>
|
||
/// 获取或设置一个值,该值指示此元素能否用作拖放操作的目标。
|
||
/// </summary>
|
||
[Description("获取或设置一个值,该值指示此元素能否用作拖放操作的目标。")]
|
||
[UIPropertyMetadata(false, true)]
|
||
public bool AllowDrop
|
||
{
|
||
get { return GetValue<bool>(5); }
|
||
set { SetValue(value, 5); }
|
||
}
|
||
|
||
internal DragDropEffects DragDropEffects;
|
||
|
||
/// <summary>
|
||
/// Z轴
|
||
/// </summary>
|
||
[Category("布局")]
|
||
[Description("Z轴")]
|
||
[UIPropertyMetadata(0, UIPropertyOptions.AffectsArrange)]
|
||
public int ZIndex
|
||
{
|
||
get { return GetValue<int>(44); }
|
||
set { SetValue(value, 44); }
|
||
}
|
||
/// <summary>
|
||
/// 默认值为 Auto。此值必须大于或等于 0。
|
||
/// </summary>
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField Width
|
||
{
|
||
get { return GetValue<FloatField>(43); }
|
||
set { SetValue(value, 43); }
|
||
}
|
||
/// <summary>
|
||
/// 默认值为 Auto。此值必须大于或等于 0。
|
||
/// </summary>
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField Height
|
||
{
|
||
get { return GetValue<FloatField>(15); }
|
||
set { SetValue(value, 15); }
|
||
}
|
||
/// <summary>
|
||
/// 非依赖属性
|
||
/// </summary>
|
||
[Browsable(false), NotCpfProperty]
|
||
public virtual SizeField Size
|
||
{
|
||
get { return new SizeField(Width, Height); }
|
||
set { Width = value.Width; Height = value.Height; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 非依赖属性
|
||
/// </summary>
|
||
[Browsable(false), NotCpfProperty]
|
||
public virtual ThicknessField Margin
|
||
{
|
||
get { return new ThicknessField(MarginLeft, MarginTop, MarginRight, MarginBottom); }
|
||
set
|
||
{
|
||
MarginLeft = value.Left;
|
||
MarginTop = value.Top;
|
||
MarginRight = value.Right;
|
||
MarginBottom = value.Bottom;
|
||
}
|
||
}
|
||
|
||
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField MarginRight
|
||
{
|
||
get { return GetValue<FloatField>(28); }
|
||
set { SetValue(value, 28); }
|
||
}
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField MarginBottom
|
||
{
|
||
get { return GetValue<FloatField>(26); }
|
||
set { SetValue(value, 26); }
|
||
}
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField MarginLeft
|
||
{
|
||
get { return GetValue<FloatField>(27); }
|
||
set { SetValue(value, 27); }
|
||
}
|
||
[Category("布局")]
|
||
[UIPropertyMetadata(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure)]
|
||
public virtual FloatField MarginTop
|
||
{
|
||
get { return GetValue<FloatField>(29); }
|
||
set { SetValue(value, 29); }
|
||
}
|
||
///// <summary>
|
||
///// 百分比是相对自身
|
||
///// </summary>
|
||
//[UIPropertyMetadata(typeof(FloatValue), "0", UIPropertyOptions.AffectsMeasure)]
|
||
//public FloatValue PaddingRight
|
||
//{
|
||
// get { return (FloatValue)GetValue(); }
|
||
// set { SetValue(value); }
|
||
//}
|
||
///// <summary>
|
||
///// 百分比是相对自身
|
||
///// </summary>
|
||
//[UIPropertyMetadata(typeof(FloatValue), "0", UIPropertyOptions.AffectsMeasure)]
|
||
//public FloatValue PaddingBottom
|
||
//{
|
||
// get { return (FloatValue)GetValue(); }
|
||
// set { SetValue(value); }
|
||
//}
|
||
///// <summary>
|
||
///// 百分比是相对自身
|
||
///// </summary>
|
||
//[UIPropertyMetadata(typeof(FloatValue), "0", UIPropertyOptions.AffectsMeasure)]
|
||
//public FloatValue PaddingLeft
|
||
//{
|
||
// get { return (FloatValue)GetValue(); }
|
||
// set { SetValue(value); }
|
||
//}
|
||
///// <summary>
|
||
///// 百分比是相对自身
|
||
///// </summary>
|
||
//[UIPropertyMetadata(typeof(FloatValue), "0", UIPropertyOptions.AffectsMeasure)]
|
||
//public FloatValue PaddingTop
|
||
//{
|
||
// get { return (FloatValue)GetValue(); }
|
||
// set { SetValue(value); }
|
||
//}
|
||
//internal bool isRoot;
|
||
/// <summary>
|
||
/// 是否为根元素
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
public bool IsRoot
|
||
{
|
||
get { return GetFlag(CoreFlags.isRoot); }
|
||
internal set { SetFlag(CoreFlags.isRoot, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根元素
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
public virtual View Root
|
||
{
|
||
get;
|
||
internal set;
|
||
}
|
||
/// <summary>
|
||
/// 获取一个值,该值指示此元素布局中的子元素的计算大小和位置是否有效。
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Description("获取一个值,该值指示此元素布局中的子元素的计算大小和位置是否有效。")]
|
||
public bool IsArrangeValid
|
||
{
|
||
get { return GetFlag(CoreFlags.IsArrangeValid); }
|
||
internal set { SetFlag(CoreFlags.IsArrangeValid, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 父级元素
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
public virtual UIElement Parent
|
||
{
|
||
get;
|
||
internal set;
|
||
}
|
||
/// <summary>
|
||
/// 是否启用
|
||
/// </summary>
|
||
[UIPropertyMetadata(true, true)]
|
||
[Description("是否启用")]
|
||
public virtual bool IsEnabled
|
||
{
|
||
get { return GetValue<bool>(18); }
|
||
set { SetValue(value, 18); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// UI元素可见性
|
||
/// </summary>
|
||
[Category("布局")]
|
||
[Description("UI元素可见性")]
|
||
[UIPropertyMetadata(Visibility.Visible, UIPropertyOptions.AffectsMeasure)]
|
||
public virtual Visibility Visibility
|
||
{
|
||
get { return (Visibility)GetValue(42); }
|
||
set { SetValue(value, 42); }
|
||
}
|
||
/// <summary>
|
||
/// 光标,用Cursors.***来设置
|
||
/// </summary>
|
||
[Description("光标")]
|
||
[UIPropertyMetadata(typeof(Cursor), "Arrow", true)]
|
||
public Cursor Cursor
|
||
{
|
||
get { return GetValue<Cursor>(7); }
|
||
set { SetValue(value, 7); }
|
||
}
|
||
///// <summary>
|
||
///// 元素是否有效,如果为false,将不能显示,而且不参与布局。在布局过程中使用,用来优化布局
|
||
///// </summary>
|
||
//[NotCPFProperty]
|
||
//public bool Valid
|
||
//{
|
||
// get; set;
|
||
//} = true;
|
||
///// <summary>
|
||
///// 外边距
|
||
///// </summary>
|
||
//public virtual Thickness Margin
|
||
//{
|
||
// get { return (Thickness)GetValue(MarginProperty); }
|
||
// set { SetValue(MarginProperty, value); }
|
||
//}
|
||
Rect renderBounds;
|
||
/// <summary>
|
||
/// 布局之后相对于根元素的矩形剪辑区域
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
[Description("布局之后相对于根元素的矩形剪辑区域")]
|
||
public Rect RenderBounds { get { return renderBounds; } }
|
||
|
||
/// <summary>
|
||
/// 渲染变换
|
||
/// </summary>
|
||
[Browsable(false)]
|
||
[Description("渲染变换")]
|
||
[UIPropertyMetadata(typeof(Transform), "Identity", UIPropertyOptions.AffectsArrange)]
|
||
public virtual Transform RenderTransform
|
||
{
|
||
get { return GetValue<Transform>(36); }
|
||
set { SetValue(value, 36); }
|
||
}
|
||
/// <summary>
|
||
/// 渲染原点
|
||
/// </summary>
|
||
[Category("布局")]
|
||
[Description("渲染原点")]
|
||
[UIPropertyMetadata(typeof(PointField), "50%,50%", UIPropertyOptions.AffectsArrange)]
|
||
public PointField RenderTransformOrigin
|
||
{
|
||
get { return GetValue<PointField>(37); }
|
||
set { SetValue(value, 37); }
|
||
}
|
||
/// <summary>
|
||
/// 获取一个值,该值指示鼠标指针是否位于此元素(包括可视树上的子元素)上
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("获取一个值,该值指示鼠标指针是否位于此元素(包括可视树上的子元素)上")]
|
||
public bool IsMouseOver
|
||
{
|
||
get { return GetValue<bool>(24); }
|
||
private set { SetValue(value, 24); }
|
||
}
|
||
/// <summary>
|
||
/// 获取一个值,该值指示鼠标拖拽指针是否位于此元素(包括可视树上的子元素)上
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("获取一个值,该值指示鼠标拖拽指针是否位于此元素(包括可视树上的子元素)上")]
|
||
public bool IsDragOver
|
||
{
|
||
get { return GetValue<bool>(17); }
|
||
private set { SetValue(value, 17); }
|
||
}
|
||
///// <summary>
|
||
///// 获取一个值,鼠标左键是否按下
|
||
///// </summary>
|
||
//[PropertyMetadata(false)]
|
||
//public bool IsMouseLeftButtonDown
|
||
//{
|
||
// get { return GetValue<bool>(); }
|
||
// private set { SetValue(value); }
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 获取元素呈现的尺寸
|
||
/// </summary>
|
||
//[NotCpfProperty]
|
||
[Description("获取元素呈现的尺寸")]
|
||
public Size ActualSize
|
||
{
|
||
get { return GetValue<Size>(4); }
|
||
protected set { SetValue(value, 4); }
|
||
}
|
||
/// <summary>
|
||
/// 元素偏移位置
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Description("元素偏移位置")]
|
||
public Point ActualOffset
|
||
{
|
||
get { return VisualOffset; }
|
||
}
|
||
/// <summary>
|
||
/// 获取一个值,该值指示布局度量值返回的当前大小是否有效。
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Description("获取一个值,该值指示布局度量值返回的当前大小是否有效。")]
|
||
public bool IsMeasureValid
|
||
{
|
||
get { return GetFlag(CoreFlags.isMeasureValid); }
|
||
private set { SetFlag(CoreFlags.isMeasureValid, value); }
|
||
}
|
||
/// <summary>
|
||
/// 获取或设置一个值,该值指示是否应向此元素的大小和位置布局应用布局舍入。
|
||
/// </summary>
|
||
[PropertyMetadata(false)]
|
||
[Description("获取或设置一个值,该值指示是否应向此元素的大小和位置布局应用布局舍入。")]
|
||
public bool UseLayoutRounding
|
||
{
|
||
get { return GetValue<bool>(41); }
|
||
set { SetValue(value, 41); }
|
||
}
|
||
/// <summary>
|
||
/// 右键菜单
|
||
/// </summary>
|
||
[Browsable(false)]
|
||
[Description("右键菜单")]
|
||
public ContextMenu ContextMenu
|
||
{
|
||
get { return GetValue<ContextMenu>(6); }
|
||
set { SetValue(value, 6); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 使图像无效化,下次更新的时候重绘
|
||
/// </summary>
|
||
public void Invalidate()
|
||
{
|
||
var host = Root;
|
||
if (host != null)
|
||
{
|
||
host.Invalidate(renderBounds);
|
||
}
|
||
}
|
||
//public void Invalidate(Rect rect)
|
||
//{
|
||
// IView host = Host;
|
||
// if (host != null)
|
||
// {
|
||
// host.Invalidate(GetHostClipBounds(rect));
|
||
// }
|
||
//}
|
||
/// <summary>
|
||
/// 是否是该元素的祖先
|
||
/// </summary>
|
||
/// <param name="ancestors"></param>
|
||
/// <returns></returns>
|
||
public bool IsAncestors(UIElement ancestors)
|
||
{
|
||
if (ancestors == this)
|
||
{
|
||
return false;
|
||
}
|
||
var control = Parent;
|
||
while (control != null)
|
||
{
|
||
if (control == this)
|
||
{
|
||
return false;
|
||
}
|
||
else if (control == ancestors)
|
||
{
|
||
return true;
|
||
}
|
||
control = control.Parent;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
protected override object OnGetDefaultValue(PropertyMetadataAttribute pm)
|
||
{
|
||
//CpfObject p;
|
||
//if (pm.PropertyName != nameof(Parent) && (p = Parent) != null && (pm is UIPropertyMetadataAttribute pma) && pma.Inherits && p.HasProperty(pm.PropertyName))
|
||
//{
|
||
// return p.GetValue(pm.PropertyName);
|
||
//}
|
||
if (inheritsValues != null && inheritsValues.TryGetValue(pm.PropertyName, out InheritsValue value))
|
||
{
|
||
return value.Value;
|
||
}
|
||
return base.OnGetDefaultValue(pm);
|
||
}
|
||
protected override bool OnSetValue(string propertyName, ref object value)
|
||
{
|
||
if (value == null && propertyName == nameof(RenderTransform))
|
||
{
|
||
value = Transform.Identity;
|
||
}
|
||
return base.OnSetValue(propertyName, ref value);
|
||
}
|
||
|
||
public override bool SetValue<T>(T value, [CallerMemberName] string propertyName = null)
|
||
{
|
||
if (Root != null && !Threading.Dispatcher.MainThread.CheckAccess())
|
||
{
|
||
return InvokeSetValue(value, propertyName);
|
||
}
|
||
return base.SetValue(value, propertyName);
|
||
}
|
||
|
||
private bool InvokeSetValue<T>(T value, string propertyName)
|
||
{
|
||
var r = false;
|
||
Invoke(() =>
|
||
{
|
||
r = base.SetValue(value, propertyName);
|
||
});
|
||
return r;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 内部使用,请勿调用
|
||
/// </summary>
|
||
/// <param name="value"></param>
|
||
/// <param name="propertyIndex"></param>
|
||
/// <returns></returns>
|
||
protected override bool SetValue(object value, in byte propertyIndex)
|
||
{
|
||
if (Root != null && !Threading.Dispatcher.MainThread.CheckAccess())
|
||
{
|
||
return InovkeSetValue(value, propertyIndex);
|
||
}
|
||
return base.SetValue(value, in propertyIndex);
|
||
}
|
||
|
||
private bool InovkeSetValue(object value, byte propertyIndex)
|
||
{
|
||
var r = false;
|
||
var pi = propertyIndex;
|
||
Invoke(() =>
|
||
{
|
||
r = base.SetValue(value, pi);
|
||
});
|
||
return r;
|
||
}
|
||
|
||
public override T GetValue<T>([CallerMemberName] string propertyName = null)
|
||
{
|
||
if (Root != null && !Threading.Dispatcher.MainThread.CheckAccess())
|
||
{
|
||
return InvokeGetValue<T>(propertyName);
|
||
}
|
||
return base.GetValue<T>(propertyName);
|
||
}
|
||
|
||
private T InvokeGetValue<T>(string propertyName)
|
||
{
|
||
T r = default;
|
||
Invoke(() =>
|
||
{
|
||
r = base.GetValue<T>(propertyName);
|
||
});
|
||
return r;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 内部使用,请勿调用
|
||
/// </summary>
|
||
/// <param name="index"></param>
|
||
/// <returns></returns>
|
||
protected override object GetValue(in byte index)
|
||
{
|
||
if (Root != null && !Threading.Dispatcher.MainThread.CheckAccess())
|
||
{
|
||
return InvokeGetValue(index);
|
||
}
|
||
return base.GetValue(index);
|
||
}
|
||
|
||
private object InvokeGetValue(byte index)
|
||
{
|
||
object r = default;
|
||
var i = index;
|
||
Invoke(() =>
|
||
{
|
||
r = base.GetValue(i);
|
||
});
|
||
return r;
|
||
}
|
||
|
||
[NotCpfProperty]
|
||
bool inheritsSet { set { SetFlag(CoreFlags.inheritsSet, value); } get { return GetFlag(CoreFlags.inheritsSet); } }
|
||
|
||
[PropertyChanged(nameof(Effect))]
|
||
void RegisterEffect(object newValue, object oldValue, PropertyMetadataAttribute attribute)
|
||
{
|
||
effect = newValue as Effects.Effect;
|
||
}
|
||
|
||
[PropertyChanged(nameof(ZIndex))]
|
||
void RegisterZIndex(object newValue, object oldValue, PropertyMetadataAttribute attribute)
|
||
{
|
||
UIElement parent = Parent;
|
||
if (parent != null)
|
||
{
|
||
parent.children.InvalidateZIndex();
|
||
}
|
||
}
|
||
[PropertyChanged(nameof(RenderTransform))]
|
||
void RegisterRenderTransform(object newValue, object oldValue, PropertyMetadataAttribute attribute)
|
||
{
|
||
VisualTransform = RenderTransform;
|
||
}
|
||
[PropertyChanged(nameof(ToolTip))]
|
||
void RegisterToolTip(object newValue, object oldValue, PropertyMetadataAttribute attribute)
|
||
{
|
||
if (toolTipElement)
|
||
{
|
||
toolTipElement.Dispose();
|
||
toolTipElement = null;
|
||
}
|
||
if (newValue is string str && string.IsNullOrEmpty(str))
|
||
{
|
||
return;
|
||
}
|
||
if (newValue != null)
|
||
{
|
||
UIElement element = newValue as UIElement;
|
||
if (element != null)
|
||
{
|
||
toolTipElement = element;
|
||
}
|
||
else
|
||
{
|
||
toolTipElement = new Border
|
||
{
|
||
Name = "tooltipContent",
|
||
UseLayoutRounding = true,
|
||
BorderStroke = new Stroke(1),
|
||
MarginTop = 1,
|
||
MarginRight = 1,
|
||
MarginLeft = 1,
|
||
MarginBottom = 1,
|
||
BorderFill = "#aaa",
|
||
Background = "#fff",
|
||
Child = new ContentControl { Content = newValue, MarginBottom = 2, MarginLeft = 4, MarginRight = 4, MarginTop = 2 }
|
||
};
|
||
}
|
||
}
|
||
}
|
||
|
||
[PropertyChanged(nameof(Visibility))]
|
||
void RegisterVisibility(object newValue, object oldValue, PropertyMetadataAttribute attribute)
|
||
{
|
||
Invalidate();
|
||
if ((Visibility)newValue == Visibility.Collapsed && Root != null)
|
||
{
|
||
if (IsMouseOver)
|
||
{
|
||
var e = new MouseEventArgs(Root.InputManager.MouseDevice, this, false, false, false, new Point());
|
||
Root.InputManager.MouseDevice.MouseLeave(this, e);
|
||
}
|
||
if (IsKeyboardFocusWithin || IsFocused)
|
||
{
|
||
Root.InputManager.KeyboardDevice.SetFocus(null);
|
||
InnerLostFocus();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
|
||
{
|
||
//if (propertyName == nameof(RenderTransform))
|
||
//{
|
||
// this.VisualTransform = RenderTransform;
|
||
//}
|
||
//else
|
||
//if (propertyName == nameof(ZIndex))
|
||
//{
|
||
// UIElement parent = Parent;
|
||
// if (parent != null)
|
||
// {
|
||
// parent.children.InvalidateZIndex();
|
||
// }
|
||
//}
|
||
//else
|
||
//if (propertyName == nameof(Effect))
|
||
//{
|
||
// effect = newValue as Effects.Effect;
|
||
//}
|
||
//else
|
||
//if (propertyName == nameof(ToolTip))
|
||
//{
|
||
// if (toolTipElement)
|
||
// {
|
||
// toolTipElement.Dispose();
|
||
// toolTipElement = null;
|
||
// }
|
||
// if (newValue != null)
|
||
// {
|
||
// UIElement element = newValue as UIElement;
|
||
// if (element != null)
|
||
// {
|
||
// toolTipElement = element;
|
||
// }
|
||
// else
|
||
// {
|
||
// toolTipElement = new Control { UseLayoutRounding = true, BorderStroke = new Stroke(1), MarginTop = 1, MarginRight = 1, MarginLeft = 1, MarginBottom = 1, BorderFill = "#aaa", Background = "#fff", Children = { new ContentControl { Content = newValue.ToString(), MarginBottom = 2, MarginLeft = 4, MarginRight = 4, MarginTop = 2 } } };
|
||
// }
|
||
// }
|
||
//}
|
||
//else
|
||
//if (propertyName == nameof(Visibility))
|
||
//{
|
||
// if ((Visibility)newValue == Visibility.Collapsed)
|
||
// {
|
||
// //IsMouseOver = false;
|
||
// if (IsMouseOver)
|
||
// {
|
||
// var e = new MouseEventArgs(Root.InputManager.MouseDevice, this, false, false, false, new Point(), 0);
|
||
// //RaiseDeviceEvent(e, EventType.MouseLeave);
|
||
// Root.InputManager.MouseDevice.MouseLeave(this, e);
|
||
// }
|
||
// //foreach (var item in Find<UIElement>().Where(a => a.IsMouseOver))
|
||
// //{
|
||
// // //item.IsMouseOver = false;
|
||
// // //item.IsMouseLeftButtonDown = false;
|
||
// //}
|
||
// if (IsKeyboardFocusWithin || IsFocused)
|
||
// {
|
||
// Root.InputManager.KeyboardDevice.SetFocus(null);
|
||
// InnerLostFocus();
|
||
// }
|
||
// }
|
||
//}
|
||
//if (Name == "more" && propertyName == "MarginLeft")
|
||
//{
|
||
// Debug.WriteLine(newValue);
|
||
//}
|
||
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
|
||
var data = propertyMetadata as UIPropertyMetadataAttribute;
|
||
if (data != null)
|
||
{
|
||
if (data.Inherits)
|
||
{
|
||
|
||
if (!inheritsSet)
|
||
{
|
||
for (int i = 0; i < Children.Count; i++)
|
||
{
|
||
Inherits(children[i], propertyName, oldValue, newValue);
|
||
}
|
||
}
|
||
}
|
||
if (data.AffectsMeasure)
|
||
{
|
||
InvalidateMeasure();
|
||
//Parent?.OnChildInvalidateMeasure(this);
|
||
}
|
||
if (data.AffectsArrange)
|
||
{
|
||
InvalidateArrange();
|
||
//Parent?.OnChildInvalidateArrange(this);
|
||
}
|
||
if (data.AffectsRender)
|
||
{
|
||
Invalidate();
|
||
}
|
||
var notify = oldValue as INotifyPropertyChanged;
|
||
if (notify != null)
|
||
{
|
||
//notify.PropertyChanged -= Notify_PropertyChanged;
|
||
Binding.CancellationPropertyChanged(notify, Notify_PropertyChanged);
|
||
if (notifyList != null)
|
||
{
|
||
if (notifyList.TryGetValue(notify, out var p))
|
||
{
|
||
p.Remove(data);
|
||
if (p.Count == 0)
|
||
{
|
||
notifyList.Remove(notify);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
notify = newValue as INotifyPropertyChanged;
|
||
if (notify != null)
|
||
{
|
||
//notify.PropertyChanged += Notify_PropertyChanged;
|
||
Binding.RegisterPropertyChanged(notify, Notify_PropertyChanged);
|
||
if (notifyList == null)
|
||
{
|
||
notifyList = new HybridDictionary<INotifyPropertyChanged, HashSet<UIPropertyMetadataAttribute>>();
|
||
}
|
||
if (!notifyList.TryGetValue(notify, out var p))
|
||
{
|
||
notifyList.Add(notify, new HashSet<UIPropertyMetadataAttribute> { data });
|
||
}
|
||
else
|
||
{
|
||
p.Add(data);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (triggers != null)
|
||
{
|
||
var c = triggers.Count;
|
||
for (int i = 0; i < c; i++)
|
||
{
|
||
if (i >= triggers.Count)
|
||
{
|
||
break;
|
||
}
|
||
var t = triggers[i];
|
||
if (t.Property == propertyName)
|
||
{
|
||
var set = t.Condition(this);
|
||
if (t.TargetRelation != null && t.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in t.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(t, item, set);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(t, this, set);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
protected override void OnAttachedChanged(Type ownerType, string propertyName, object defaultValue, object oldValue, object newValue)
|
||
{
|
||
base.OnAttachedChanged(ownerType, propertyName, defaultValue, oldValue, newValue);
|
||
if (triggers != null)
|
||
{
|
||
var c = triggers.Count;
|
||
for (int i = 0; i < c; i++)
|
||
{
|
||
if (i >= triggers.Count)
|
||
{
|
||
break;
|
||
}
|
||
var t = triggers[i];
|
||
if (t.Property == ownerType.Name + "." + propertyName)
|
||
{
|
||
var set = t.Condition(this);
|
||
if (t.TargetRelation != null && t.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in t.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(t, item, set);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(t, this, set);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SetTrigger(Trigger t, UIElement target, bool setTriggerValue, bool onAdd = false)
|
||
{
|
||
if (setTriggerValue)
|
||
{
|
||
if (t.Animation != null && Root != null && (!onAdd || PlayAnimationOnAddTrigger))
|
||
{
|
||
t.Animation.Start(this, target, t.AnimationDuration, t.AnimationIterationCount, t.AnimationEndBehavior, t);
|
||
}
|
||
foreach (var item in t.Setters)
|
||
{
|
||
if (target.HasProperty(item.Key))
|
||
{
|
||
target.SetTriggerValue(item.Key, t, item.Value);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//foreach (var item in t.Setters)
|
||
//{
|
||
// target.ClearTriggerValue(t, item.Key);
|
||
//}
|
||
if (t.Animation != null)
|
||
{
|
||
t.Animation.Remove(target);
|
||
}
|
||
if (t.SetPropertys != null)
|
||
{
|
||
if (t.SetPropertys.TryGetValue(target, out List<string> ps))
|
||
{
|
||
foreach (var item in ps)
|
||
{
|
||
target.ClearTriggerValue(t, item);
|
||
}
|
||
}
|
||
|
||
//t.SetPropertys.Clear();
|
||
}
|
||
}
|
||
}
|
||
|
||
private void Notify_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||
{
|
||
if (notifyList != null)
|
||
{
|
||
if (notifyList.TryGetValue((sender as INotifyPropertyChanged), out var p))
|
||
{
|
||
bool AffectsMeasure = false;
|
||
bool AffectsArrange = false;
|
||
bool AffectsRender = false;
|
||
foreach (var item in p)
|
||
{
|
||
AffectsMeasure = AffectsMeasure || item.AffectsMeasure;
|
||
AffectsRender = AffectsRender || item.AffectsRender;
|
||
AffectsArrange = AffectsArrange || item.AffectsArrange;
|
||
}
|
||
|
||
if (AffectsMeasure)
|
||
{
|
||
InvalidateMeasure();
|
||
//Parent?.OnChildInvalidateMeasure(this);
|
||
}
|
||
else if (AffectsArrange)
|
||
{
|
||
InvalidateArrange();
|
||
//Parent?.OnChildInvalidateArrange(this);
|
||
}
|
||
else if (AffectsRender)
|
||
{
|
||
Invalidate();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/// <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))
|
||
{
|
||
//var p = element.GetPropertyMetadata(propertyName);
|
||
|
||
var ui = p as UIPropertyMetadataAttribute;
|
||
if (ui != null && ui.Inherits)
|
||
{
|
||
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);
|
||
}
|
||
}
|
||
//if (propertyName != nameof(DataContext) || !element.HasLocalOrStyleValue(propertyName, out p))
|
||
//{
|
||
//}
|
||
}
|
||
}
|
||
|
||
internal override void OnSetValue(string propertyName, PropertyMetadataAttribute property, ValueFrom valueForm, object newValue)
|
||
{
|
||
if (property is UIPropertyMetadataAttribute ui && ui.Inherits)
|
||
{
|
||
inheritsValues.Remove(propertyName);
|
||
inheritsValues.Add(propertyName, new InheritsValue { Value = newValue, ValueForm = valueForm });
|
||
}
|
||
}
|
||
|
||
internal override void OnClearLocalValue(string propertyName, EffectiveValue value)
|
||
{
|
||
if (inheritsValues.TryGetValue(propertyName, out InheritsValue value1) && value1.ValueForm == ValueFrom.Property)
|
||
{
|
||
inheritsValues.Remove(propertyName);
|
||
}
|
||
}
|
||
internal override void OnClearTriggerValue(string propertyName, EffectiveValue value)
|
||
{
|
||
if (value.TriggerValue == null || value.TriggerValue.Count == 0)
|
||
{
|
||
if (inheritsValues.TryGetValue(propertyName, out InheritsValue value1) && value1.ValueForm == ValueFrom.Trigger)
|
||
{
|
||
inheritsValues.Remove(propertyName);
|
||
}
|
||
}
|
||
}
|
||
|
||
internal override void OnClearAnimationValue(string propertyName, EffectiveValue value)
|
||
{
|
||
if (value.AnimationValue == null || value.AnimationValue.Count == 0)
|
||
{
|
||
if (inheritsValues.TryGetValue(propertyName, out InheritsValue value1) && value1.ValueForm == ValueFrom.Animation)
|
||
{
|
||
inheritsValues.Remove(propertyName);
|
||
}
|
||
}
|
||
}
|
||
|
||
internal override void OnClearStyleValue(string propertyName, EffectiveValue value)
|
||
{
|
||
if (value.styleValues == null || value.styleValues.Count == 0)
|
||
{
|
||
if (inheritsValues.TryGetValue(propertyName, out InheritsValue value1) && value1.ValueForm == ValueFrom.Style)
|
||
{
|
||
inheritsValues.Remove(propertyName);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取在布局流程的度量传递过程中此元素计算所得的大小,包含margin。其实就是能包含所有内容的最小尺寸
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[NotCpfProperty]
|
||
public Size DesiredSize
|
||
{
|
||
get { return desiredSize; }
|
||
}
|
||
/// <summary>
|
||
/// 在派生类中重写时,测量子元素或者内容在布局中所需的大小,availableSize不包含当前对象的Margin和Padding,并确定由 UIElement 派生的类的大小。
|
||
/// </summary>
|
||
/// <param name="availableSize">一般不要使用该属性参与计算</param>
|
||
/// <returns>此元素基于其对子元素大小的计算确定它在布局期间所需要的大小。</returns>
|
||
protected virtual Size MeasureOverride(in Size availableSize)
|
||
{
|
||
Size contentDesiredSize = new Size();
|
||
|
||
if (children != null)
|
||
{
|
||
foreach (UIElement item in Children)
|
||
{
|
||
item.Measure(availableSize);
|
||
contentDesiredSize.Width = Math.Max(contentDesiredSize.Width, item.DesiredSize.Width);
|
||
contentDesiredSize.Height = Math.Max(contentDesiredSize.Height, item.DesiredSize.Height);
|
||
}
|
||
}
|
||
|
||
return contentDesiredSize;
|
||
}
|
||
/// <summary>
|
||
/// 测量期望尺寸
|
||
/// </summary>
|
||
/// <param name="availableSize">一般不要使用该属性</param>
|
||
public void Measure(in Size availableSize)
|
||
{
|
||
if (!IsMeasureValid || (_previousMeasure != availableSize && (Width.IsAuto || Width.Unit != Unit.Default || Height.IsAuto || Height.Unit != Unit.Default)))
|
||
{
|
||
var previousDesiredSize = desiredSize;
|
||
|
||
|
||
//try
|
||
//{
|
||
//_measuring = true;
|
||
desiredSize = MeasureCore(availableSize);//.Constrain(availableSize);
|
||
IsMeasureValid = true;
|
||
//Console.WriteLine(this.ToString() + ":" + desiredSize.ToString());
|
||
//}
|
||
//finally
|
||
//{
|
||
// //_measuring = false;
|
||
//}
|
||
|
||
//if (IsInvalidSize(desiredSize))
|
||
//{
|
||
// throw new InvalidOperationException("Invalid size returned for Measure.");
|
||
//}
|
||
|
||
_previousMeasure = availableSize;
|
||
|
||
//Logger.Verbose(LogArea.Layout, this, "Measure requested {DesiredSize}", DesiredSize);
|
||
|
||
if (DesiredSize != previousDesiredSize)
|
||
{
|
||
Parent?.OnChildDesiredSizeChanged(this, previousDesiredSize);
|
||
this.RaiseEvent(EventArgs.Empty, nameof(DesiredSizeChanged));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
internal static float RoundLayoutValue(float value, float dpiScale)
|
||
{
|
||
float newValue;
|
||
|
||
// If DPI == 1, don't use DPI-aware rounding.
|
||
if (!FloatUtil.AreClose(dpiScale, 1f))
|
||
{
|
||
newValue = (float)Math.Round(value * dpiScale) / dpiScale;
|
||
// If rounding produces a value unacceptable to layout (NaN, Infinity or MaxValue), use the original value.
|
||
if (FloatUtil.IsNaN(newValue) ||
|
||
float.IsInfinity(newValue) ||
|
||
FloatUtil.AreClose(newValue, float.MaxValue))
|
||
{
|
||
newValue = value;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
newValue = (float)Math.Round(value);
|
||
}
|
||
|
||
return newValue;
|
||
}
|
||
protected virtual void OnChildDesiredSizeChanged(UIElement child, in Size old)
|
||
{
|
||
if (((!Width.IsAuto && Width.Unit != Unit.Percent)) && ((!Height.IsAuto && Height.Unit != Unit.Percent)))
|
||
{
|
||
InvalidateArrange();
|
||
}
|
||
else
|
||
{
|
||
if (IsMeasureValid)
|
||
{
|
||
InvalidateMeasure();
|
||
}
|
||
else
|
||
{
|
||
//if (desiredSizeChangedChildren == null)
|
||
//{
|
||
// desiredSizeChangedChildren = new Dictionary<UIElement, Size>();
|
||
//}
|
||
//desiredSizeChangedChildren[child] = old;
|
||
}
|
||
|
||
}
|
||
}
|
||
//Dictionary<UIElement, Size> desiredSizeChangedChildren;
|
||
|
||
static Type panelType = typeof(Panel);
|
||
/// <summary>
|
||
/// 测量期望尺寸
|
||
/// </summary>
|
||
/// <param name="availableSize">相当于父容器能提供的尺寸,如果值为PositiveInfinity,则父容器未定义尺寸依赖子元素的尺寸</param>
|
||
/// <returns>The desired size for the control.</returns>
|
||
protected virtual Size MeasureCore(in Size availableSize)
|
||
{
|
||
if (Visibility != Visibility.Collapsed)
|
||
{
|
||
var l = MarginLeft;
|
||
var t = MarginTop;
|
||
var r = MarginRight;
|
||
var b = MarginBottom;
|
||
var w = Width;
|
||
var h = Height;
|
||
var maxw = MaxWidth;
|
||
var maxh = MaxHeight;
|
||
var minw = MinWidth;
|
||
var minh = MinHeight;
|
||
|
||
var constrainedWidth = float.PositiveInfinity;//可以提供的最大尺寸
|
||
var constrainedHeight = float.PositiveInfinity;
|
||
|
||
if (!l.IsAuto && !r.IsAuto)
|
||
{
|
||
constrainedWidth = Math.Max(0, availableSize.Width - l.GetActualValue(availableSize.Width) - r.GetActualValue(availableSize.Width));
|
||
}
|
||
if (!w.IsAuto)
|
||
{
|
||
//if (w.Unit == Unit.Percent && Parent != null && Parent.Width.IsAuto)
|
||
//{
|
||
// constrainedWidth = float.PositiveInfinity;
|
||
//}
|
||
//else
|
||
//{
|
||
constrainedWidth = Math.Max(0, w.GetActualValue(availableSize.Width));
|
||
//}
|
||
}
|
||
if (!float.IsInfinity(constrainedWidth) && !maxw.IsAuto && !float.IsInfinity(availableSize.Width))
|
||
{
|
||
var max = maxw.GetActualValue(availableSize.Width);
|
||
if (constrainedWidth > max)
|
||
{
|
||
constrainedWidth = max;
|
||
}
|
||
}
|
||
if (!minw.IsAuto)
|
||
{
|
||
var min = minw.GetActualValue(availableSize.Width);
|
||
if (constrainedWidth < min)
|
||
{
|
||
constrainedWidth = min;
|
||
}
|
||
}
|
||
|
||
if (!t.IsAuto && !b.IsAuto)
|
||
{
|
||
constrainedHeight = Math.Max(0, availableSize.Height - t.GetActualValue(availableSize.Height) - b.GetActualValue(availableSize.Height));
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
//if (h.Unit == Unit.Percent && Parent != null && Parent.Height.IsAuto)
|
||
//{
|
||
// constrainedHeight = float.PositiveInfinity;
|
||
//}
|
||
//else
|
||
//{
|
||
constrainedHeight = Math.Max(0, h.GetActualValue(availableSize.Height));
|
||
//}
|
||
}
|
||
|
||
if (!float.IsInfinity(constrainedHeight) && !maxh.IsAuto && !float.IsInfinity(availableSize.Height))
|
||
{
|
||
var max = maxh.GetActualValue(availableSize.Height);
|
||
if (constrainedHeight > max)
|
||
{
|
||
constrainedHeight = max;
|
||
}
|
||
}
|
||
if (!minh.IsAuto)
|
||
{
|
||
var min = minh.GetActualValue(availableSize.Height);
|
||
if (constrainedHeight < min)
|
||
{
|
||
constrainedHeight = min;
|
||
}
|
||
}
|
||
|
||
//内容尺寸
|
||
var measured = MeasureOverride(new Size(constrainedWidth, constrainedHeight));
|
||
if ((measured.Height > availableSize.Height && !maxh.IsAuto && float.IsInfinity(constrainedHeight) && !float.IsInfinity(availableSize.Height) && h.IsAuto) ||
|
||
(measured.Width > availableSize.Width && !maxw.IsAuto && float.IsInfinity(constrainedWidth) && !float.IsInfinity(availableSize.Width) && w.IsAuto))
|
||
{
|
||
measured = MeasureOverride(new Size(maxw.GetActualValue(availableSize.Width), maxh.GetActualValue(availableSize.Height)));
|
||
}
|
||
//if (desiredSizeChangedChildren != null)
|
||
//{
|
||
// foreach (var item in desiredSizeChangedChildren)
|
||
// {
|
||
// if (item.Value != item.Key.desiredSize)
|
||
// {
|
||
// InvalidateMeasure();
|
||
// break;
|
||
// }
|
||
// }
|
||
// desiredSizeChangedChildren = null;
|
||
//}
|
||
|
||
var width = measured.Width;
|
||
var height = measured.Height;
|
||
|
||
var wPercent = float.NaN;
|
||
var hPercent = float.NaN;
|
||
if (!w.IsAuto)
|
||
{
|
||
if (w.Unit == Unit.Default || (!float.IsInfinity(availableSize.Width) && !float.IsNaN(availableSize.Width)))
|
||
{
|
||
width = w.GetActualValue(availableSize.Width);
|
||
}
|
||
else
|
||
{
|
||
wPercent = w.Value;
|
||
}
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
if (h.Unit == Unit.Default || (!float.IsInfinity(availableSize.Height) && !float.IsNaN(availableSize.Height)))
|
||
{
|
||
height = h.GetActualValue(availableSize.Height);
|
||
}
|
||
else
|
||
{
|
||
hPercent = h.Value;
|
||
}
|
||
}
|
||
float pW;//计算如果是百分比布局为100%的时候占用的尺寸
|
||
if (!float.IsNaN(wPercent))
|
||
{
|
||
pW = width / wPercent;
|
||
}
|
||
else
|
||
{
|
||
pW = width;
|
||
}
|
||
float pH;
|
||
if (!float.IsNaN(hPercent))
|
||
{
|
||
pH = height / hPercent;
|
||
}
|
||
else
|
||
{
|
||
pH = height;
|
||
}
|
||
|
||
|
||
if (!minw.IsAuto)
|
||
{
|
||
if (minw.Unit == Unit.Default)
|
||
{
|
||
if (width < minw.Value)
|
||
{
|
||
width = minw.Value;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!float.IsNaN(pW))
|
||
{
|
||
var min = pW * minw.Value;
|
||
if (min > width)
|
||
{
|
||
width = min;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!minh.IsAuto)
|
||
{
|
||
if (minh.Unit == Unit.Default)
|
||
{
|
||
if (height < minh.Value)
|
||
{
|
||
height = minh.Value;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!float.IsNaN(pH))
|
||
{
|
||
var min = pH * minh.Value;
|
||
if (min > height)
|
||
{
|
||
height = min;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!maxw.IsAuto)
|
||
{
|
||
if (maxw.Unit == Unit.Default)
|
||
{
|
||
if (width > maxw.Value)
|
||
{
|
||
width = maxw.Value;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!float.IsNaN(pW))
|
||
{
|
||
var max = pW * maxw.Value;
|
||
if (max < width)
|
||
{
|
||
width = max;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!maxh.IsAuto)
|
||
{
|
||
if (maxh.Unit == Unit.Default)
|
||
{
|
||
if (height > maxh.Value)
|
||
{
|
||
height = maxh.Value;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!float.IsNaN(pH))
|
||
{
|
||
var max = pH * maxh.Value;
|
||
if (max < height)
|
||
{
|
||
height = max;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!l.IsAuto)
|
||
{
|
||
if (l.Unit == Unit.Default)
|
||
{
|
||
width += l.Value;
|
||
}
|
||
else
|
||
{
|
||
if (float.IsNaN(availableSize.Width) || float.IsPositiveInfinity(availableSize.Width))
|
||
{
|
||
width += pW * l.Value;
|
||
}
|
||
else
|
||
{
|
||
width += availableSize.Width * l.Value;
|
||
}
|
||
}
|
||
}
|
||
if (!r.IsAuto)
|
||
{
|
||
if (r.Unit == Unit.Default)
|
||
{
|
||
width += r.Value;
|
||
}
|
||
else
|
||
{
|
||
if (float.IsNaN(availableSize.Width) || float.IsPositiveInfinity(availableSize.Width))
|
||
{
|
||
width += pW * r.Value;
|
||
}
|
||
else
|
||
{
|
||
width += availableSize.Width * r.Value;
|
||
}
|
||
}
|
||
}
|
||
if (!t.IsAuto)
|
||
{
|
||
if (t.Unit == Unit.Default)
|
||
{
|
||
height += t.Value;
|
||
}
|
||
else
|
||
{
|
||
if (float.IsPositiveInfinity(availableSize.Height) || float.IsNaN(availableSize.Height))
|
||
{
|
||
height += pH * t.Value;
|
||
}
|
||
else
|
||
{
|
||
height += availableSize.Height * t.Value;
|
||
}
|
||
}
|
||
}
|
||
if (!b.IsAuto)
|
||
{
|
||
if (b.Unit == Unit.Default)
|
||
{
|
||
height += b.Value;
|
||
}
|
||
else
|
||
{
|
||
if (float.IsPositiveInfinity(availableSize.Height) || float.IsNaN(availableSize.Height))
|
||
{
|
||
height += pH * b.Value;
|
||
}
|
||
else
|
||
{
|
||
height += availableSize.Height * b.Value;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
//if (wPercent != 0)
|
||
//{
|
||
// width = width / wPercent;
|
||
// width = Math.Max(width, constrainedWidth);
|
||
//}
|
||
//if (hPercent != 0)
|
||
//{
|
||
// height = height / hPercent;
|
||
// height = Math.Max(height, constrainedHeight);
|
||
//}
|
||
|
||
if (UseLayoutRounding)
|
||
{
|
||
var scale = Root.RenderScaling;
|
||
width = (float)Math.Ceiling(width * scale) / scale;
|
||
height = (float)Math.Ceiling(height * scale) / scale;
|
||
}
|
||
|
||
return new Size(width, height);
|
||
}
|
||
else
|
||
{
|
||
return new Size();
|
||
}
|
||
}
|
||
//protected virtual Size MeasureCore(in Size availableSize)
|
||
//{
|
||
// if (Visibility != Visibility.Collapsed)
|
||
// {
|
||
// var l = MarginLeft;
|
||
// var t = MarginTop;
|
||
// var r = MarginRight;
|
||
// var b = MarginBottom;
|
||
// var w = Width;
|
||
// var h = Height;
|
||
// var maxw = MaxWidth;
|
||
// var maxh = MaxHeight;
|
||
// var minw = MinWidth;
|
||
// var minh = MinHeight;
|
||
|
||
// var constrainedWidth = availableSize.Width;//可以提供的最大尺寸
|
||
// var constrainedHeight = availableSize.Height;
|
||
|
||
// if (!l.IsAuto && !r.IsAuto)
|
||
// {
|
||
// constrainedWidth = constrainedWidth - l.GetActualValue(availableSize.Width);
|
||
// constrainedWidth = constrainedWidth - r.GetActualValue(availableSize.Width);
|
||
// }
|
||
// if (!w.IsAuto)
|
||
// {
|
||
// constrainedWidth = w.GetActualValue(availableSize.Width);
|
||
// }
|
||
// if (!maxw.IsAuto)
|
||
// {
|
||
// var max = maxw.GetActualValue(availableSize.Width);
|
||
// if (constrainedWidth > max)
|
||
// {
|
||
// constrainedWidth = max;
|
||
// }
|
||
// }
|
||
// if (!minw.IsAuto)
|
||
// {
|
||
// var min = minw.GetActualValue(availableSize.Width);
|
||
// if (constrainedWidth < min)
|
||
// {
|
||
// constrainedWidth = min;
|
||
// }
|
||
// }
|
||
|
||
// if (!t.IsAuto && !b.IsAuto)
|
||
// {
|
||
// constrainedHeight = constrainedHeight - t.GetActualValue(availableSize.Height);
|
||
// //}
|
||
// //if ()
|
||
// //{
|
||
// constrainedHeight = constrainedHeight - b.GetActualValue(availableSize.Height);
|
||
// }
|
||
// if (!h.IsAuto)
|
||
// {
|
||
// constrainedHeight = h.GetActualValue(availableSize.Height);
|
||
// }
|
||
|
||
// if (!maxh.IsAuto)
|
||
// {
|
||
// var max = maxh.GetActualValue(availableSize.Height);
|
||
// if (constrainedHeight > max)
|
||
// {
|
||
// constrainedHeight = max;
|
||
// }
|
||
// }
|
||
// if (!minh.IsAuto)
|
||
// {
|
||
// var min = minh.GetActualValue(availableSize.Height);
|
||
// if (constrainedHeight < min)
|
||
// {
|
||
// constrainedHeight = min;
|
||
// }
|
||
// }
|
||
|
||
// //var margin = new Thickness();
|
||
// //if (!IsRoot)
|
||
// //{
|
||
// // margin = new Thickness(l.GetActualValue(availableSize.Width), t.GetActualValue(availableSize.Height), r.GetActualValue(availableSize.Width), b.GetActualValue(availableSize.Height));
|
||
// //}
|
||
|
||
// //.Deflate(margin);
|
||
// //var padding = new Thickness(pl.GetActualValue(availableSize.Width), pt.GetActualValue(availableSize.Height), pr.GetActualValue(availableSize.Width), pb.GetActualValue(availableSize.Height));
|
||
|
||
// //内容尺寸
|
||
// var measured = MeasureOverride(new Size(constrainedWidth, constrainedHeight));
|
||
// var width = measured.Width;
|
||
// var height = measured.Height;
|
||
|
||
|
||
|
||
// if (!w.IsAuto)
|
||
// {
|
||
// width = w.GetActualValue(availableSize.Width);
|
||
// }
|
||
// if (!h.IsAuto)
|
||
// {
|
||
// height = h.GetActualValue(availableSize.Height);
|
||
// }
|
||
// if (!minw.IsAuto)
|
||
// {
|
||
// var min = minw.GetActualValue(availableSize.Width);
|
||
// if (width < min)
|
||
// {
|
||
// width = min;
|
||
// }
|
||
// }
|
||
// if (!minh.IsAuto)
|
||
// {
|
||
// var min = minh.GetActualValue(availableSize.Height);
|
||
// if (height < min)
|
||
// {
|
||
// height = min;
|
||
// }
|
||
// }
|
||
// if (!maxw.IsAuto)
|
||
// {
|
||
// var max = maxw.GetActualValue(availableSize.Width);
|
||
// if (width > max)
|
||
// {
|
||
// width = max;
|
||
// }
|
||
// }
|
||
// if (!maxh.IsAuto)
|
||
// {
|
||
// var max = maxh.GetActualValue(availableSize.Height);
|
||
// if (height > max)
|
||
// {
|
||
// height = max;
|
||
// }
|
||
// }
|
||
|
||
// if (!l.IsAuto)
|
||
// {
|
||
// width += l.GetActualValue(availableSize.Width);
|
||
// }
|
||
// if (!r.IsAuto)
|
||
// {
|
||
// width += r.GetActualValue(availableSize.Width);
|
||
// }
|
||
// if (!t.IsAuto)
|
||
// {
|
||
// height += t.GetActualValue(availableSize.Height);
|
||
// }
|
||
// if (!b.IsAuto)
|
||
// {
|
||
// height += b.GetActualValue(availableSize.Height);
|
||
// }
|
||
|
||
|
||
// if (UseLayoutRounding)
|
||
// {
|
||
// var scale = Root.Scaling;
|
||
// width = (float)Math.Ceiling(width * scale) / scale;
|
||
// height = (float)Math.Ceiling(height * scale) / scale;
|
||
// }
|
||
|
||
// return new Size(Math.Max(0, width), Math.Max(0, height));
|
||
// }
|
||
// else
|
||
// {
|
||
// return new Size();
|
||
// }
|
||
//}
|
||
/// <summary>
|
||
/// Arranges the control and its children.
|
||
/// </summary>
|
||
/// <param name="rect">The control's new bounds.</param>
|
||
public void Arrange(Rect rect)
|
||
{
|
||
Root.LayoutManager._toArrange.Remove(this);
|
||
if (IsInvalidRect(rect))
|
||
{
|
||
throw new InvalidOperationException("Invalid Arrange rectangle.");
|
||
}
|
||
|
||
if (!IsMeasureValid)
|
||
{
|
||
Measure(_previousMeasure ?? rect.Size);
|
||
}
|
||
|
||
if (!IsArrangeValid || _previousArrange != rect)
|
||
{
|
||
IsArrangeValid = true;
|
||
_previousArrange = rect;
|
||
|
||
if (Visibility != Visibility.Collapsed)
|
||
{
|
||
ArrangeCore(rect);
|
||
contentBounds = new Rect(VisualOffset, ActualSize);
|
||
}
|
||
else
|
||
{
|
||
renderBounds = new Rect();
|
||
}
|
||
|
||
OnLayoutUpdated();
|
||
if (Parent != null && Parent.IsRoot)
|
||
{
|
||
Parent.viewRenderRect = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取在View上对应的剪辑区域
|
||
/// </summary>
|
||
/// <param name="rect"></param>
|
||
/// <returns></returns>
|
||
public Rect GetHostClipBounds(Rect rect)
|
||
{
|
||
UIElement parent = this.Parent;
|
||
var bounds = this.GetClipBounds(rect);
|
||
while (parent != null)
|
||
{
|
||
bounds = parent.GetClipBounds(bounds);
|
||
parent = parent.Parent;
|
||
}
|
||
return bounds;
|
||
}
|
||
[NotCpfProperty]
|
||
bool transform { set { SetFlag(CoreFlags.transform, value); } get { return GetFlag(CoreFlags.transform); } }
|
||
internal void RendRect()
|
||
{
|
||
previousRenderRect = renderBounds;
|
||
UIElement parent = this.Parent;
|
||
renderBounds = this.GetClipBounds();
|
||
if (parent != null)
|
||
{
|
||
transform = parent.transform || VisualTransform != Transform.Identity;
|
||
}
|
||
else
|
||
{
|
||
transform = VisualTransform != Transform.Identity;
|
||
}
|
||
if (transform)
|
||
{
|
||
while (parent != null)
|
||
{
|
||
renderBounds = parent.GetClipBounds(renderBounds);
|
||
parent = parent.Parent;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (parent != null)
|
||
{
|
||
renderBounds = new Rect(renderBounds.X + parent.renderBounds.X, renderBounds.Y + parent.renderBounds.Y, renderBounds.Width, renderBounds.Height);
|
||
}
|
||
}
|
||
if (effect != null)
|
||
{
|
||
renderBounds = effect.OverrideRenderRect(renderBounds);
|
||
}
|
||
var rect = previousRenderRect;
|
||
rect.Union(renderBounds);
|
||
Root.Invalidate(rect);
|
||
}
|
||
/// <summary>
|
||
/// 获取该元素相对Root的最终变换矩阵
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public Matrix GetMatrixToRoot()
|
||
{
|
||
if (IsRoot || Root == null)
|
||
{
|
||
return Matrix.Identity;
|
||
}
|
||
List<UIElement> elements = new List<UIElement>();
|
||
elements.Add(this);
|
||
var parent = Parent;
|
||
while (parent != null && !parent.IsRoot)
|
||
{
|
||
elements.Add(parent);
|
||
parent = parent.Parent;
|
||
}
|
||
elements.Reverse();
|
||
var mat = Matrix.Identity;
|
||
foreach (var item in elements)
|
||
{
|
||
Rect rect = item.GetContentBounds();
|
||
var op = item.RenderTransformOrigin;
|
||
mat.TranslatePrepend(rect.X + op.X.GetActualValue(rect.Width), rect.Y + op.Y.GetActualValue(rect.Height));
|
||
mat.Prepend(item.RenderTransform.Value);
|
||
mat.TranslatePrepend(-op.X.GetActualValue(rect.Width), -op.Y.GetActualValue(rect.Height));
|
||
}
|
||
return mat;
|
||
}
|
||
/// <summary>
|
||
/// 获取该元素相对Parent的变换矩阵
|
||
/// </summary>
|
||
/// <param name="element"></param>
|
||
/// <returns></returns>
|
||
public Matrix GetMatrixToParent(UIElement element)
|
||
{
|
||
if (IsRoot || Root == null || element.Root != Root)
|
||
{
|
||
return Matrix.Identity;
|
||
}
|
||
List<UIElement> elements = new List<UIElement>();
|
||
elements.Add(this);
|
||
var parent = Parent;
|
||
while (parent != null && !parent.IsRoot && element != parent)
|
||
{
|
||
elements.Add(parent);
|
||
parent = parent.Parent;
|
||
}
|
||
elements.Reverse();
|
||
var mat = Matrix.Identity;
|
||
foreach (var item in elements)
|
||
{
|
||
Rect rect = item.GetContentBounds();
|
||
var op = item.RenderTransformOrigin;
|
||
mat.TranslatePrepend(rect.X + op.X.GetActualValue(rect.Width), rect.Y + op.Y.GetActualValue(rect.Height));
|
||
mat.Prepend(item.RenderTransform.Value);
|
||
mat.TranslatePrepend(-op.X.GetActualValue(rect.Width), -op.Y.GetActualValue(rect.Height));
|
||
}
|
||
return mat;
|
||
}
|
||
|
||
/// <summary>
|
||
/// The default implementation of the control's arrange pass.
|
||
/// </summary>
|
||
/// <param name="finalRect">The control's new bounds.</param>
|
||
/// <remarks>
|
||
/// This method calls <see cref="ArrangeOverride(in Size)"/> which is probably the method you
|
||
/// want to override in order to modify a control's arrangement.
|
||
/// </remarks>
|
||
protected virtual void ArrangeCore(in Rect finalRect)
|
||
{
|
||
var l = MarginLeft;
|
||
var t = MarginTop;
|
||
var r = MarginRight;
|
||
var b = MarginBottom;
|
||
var w = Width;
|
||
var h = Height;
|
||
var maxw = MaxWidth;
|
||
var maxh = MaxHeight;
|
||
var minw = MinWidth;
|
||
var minh = MinHeight;
|
||
|
||
var scale = Root.RenderScaling;
|
||
|
||
float constrainedWidth;
|
||
float constrainedHeight;
|
||
bool isPanel = true;
|
||
var p = Parent;
|
||
if (p == null || !(p is Panel) || p.Type == panelType)
|
||
{//普通元素布局
|
||
isPanel = false;
|
||
if (!l.IsAuto && !r.IsAuto)
|
||
{
|
||
constrainedWidth = finalRect.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width);
|
||
}
|
||
else
|
||
{
|
||
constrainedWidth = desiredSize.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width);
|
||
}
|
||
if (!w.IsAuto)
|
||
{
|
||
constrainedWidth = w.GetActualValue(finalRect.Width);
|
||
}
|
||
if (!maxw.IsAuto)
|
||
{
|
||
var max = maxw.GetActualValue(finalRect.Width);
|
||
if (constrainedWidth > max)
|
||
{
|
||
constrainedWidth = max;
|
||
}
|
||
}
|
||
if (!minw.IsAuto)
|
||
{
|
||
var min = minw.GetActualValue(finalRect.Width);
|
||
if (constrainedWidth < min)
|
||
{
|
||
constrainedWidth = min;
|
||
}
|
||
}
|
||
|
||
if (!t.IsAuto && !b.IsAuto)
|
||
{
|
||
constrainedHeight = finalRect.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height);
|
||
}
|
||
else
|
||
{
|
||
constrainedHeight = desiredSize.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height);
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
constrainedHeight = h.GetActualValue(finalRect.Height);
|
||
}
|
||
|
||
if (!maxh.IsAuto)
|
||
{
|
||
var max = maxh.GetActualValue(finalRect.Height);
|
||
if (constrainedHeight > max)
|
||
{
|
||
constrainedHeight = max;
|
||
}
|
||
}
|
||
if (!minh.IsAuto)
|
||
{
|
||
var min = minh.GetActualValue(finalRect.Height);
|
||
if (constrainedHeight < min)
|
||
{
|
||
constrainedHeight = min;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{//panel的继承的布局容器布局
|
||
//if (this is TextBlock textBlock && textBlock.Text == "跨列")
|
||
//{
|
||
|
||
//}
|
||
if (!w.IsAuto)
|
||
{
|
||
constrainedWidth = w.GetActualValue(finalRect.Width);
|
||
}
|
||
else
|
||
{
|
||
if (!l.IsAuto && !r.IsAuto)
|
||
{
|
||
constrainedWidth = finalRect.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width);
|
||
}
|
||
else
|
||
{
|
||
constrainedWidth = desiredSize.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width);
|
||
}
|
||
}
|
||
if (!w.IsAuto)
|
||
{
|
||
constrainedWidth = w.GetActualValue(finalRect.Width);
|
||
}
|
||
if (!maxw.IsAuto)
|
||
{
|
||
var max = maxw.GetActualValue(finalRect.Width);
|
||
if (constrainedWidth > max)
|
||
{
|
||
constrainedWidth = max;
|
||
}
|
||
}
|
||
if (!minw.IsAuto)
|
||
{
|
||
var min = minw.GetActualValue(finalRect.Width);
|
||
if (constrainedWidth < min)
|
||
{
|
||
constrainedWidth = min;
|
||
}
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
constrainedHeight = h.GetActualValue(finalRect.Height);
|
||
}
|
||
else
|
||
{
|
||
if (!t.IsAuto && !b.IsAuto)
|
||
{
|
||
constrainedHeight = finalRect.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height);
|
||
}
|
||
else
|
||
{
|
||
constrainedHeight = desiredSize.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height);
|
||
}
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
constrainedHeight = h.GetActualValue(finalRect.Height);
|
||
}
|
||
|
||
if (!maxh.IsAuto)
|
||
{
|
||
var max = maxh.GetActualValue(finalRect.Height);
|
||
if (constrainedHeight > max)
|
||
{
|
||
constrainedHeight = max;
|
||
}
|
||
}
|
||
if (!minh.IsAuto)
|
||
{
|
||
var min = minh.GetActualValue(finalRect.Height);
|
||
if (constrainedHeight < min)
|
||
{
|
||
constrainedHeight = min;
|
||
}
|
||
}
|
||
}
|
||
//var s = _previousArrangeResultSize;
|
||
//if (_previousArrangeFinalSize != size)
|
||
//{
|
||
var size = new Size(constrainedWidth, constrainedHeight);
|
||
size = ArrangeOverride(size);
|
||
// _previousArrangeResultSize = s;
|
||
// _previousArrangeFinalSize = size;
|
||
//}
|
||
if (!l.IsAuto && !r.IsAuto)
|
||
{
|
||
size.Width = finalRect.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width);
|
||
}
|
||
if (!t.IsAuto && !b.IsAuto)
|
||
{
|
||
size.Height = finalRect.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height);
|
||
}
|
||
|
||
if (!w.IsAuto)
|
||
{
|
||
size.Width = Math.Max(0, w.GetActualValue(finalRect.Width));
|
||
}
|
||
if (!h.IsAuto)
|
||
{
|
||
size.Height = Math.Max(0, h.GetActualValue(finalRect.Height));
|
||
}
|
||
|
||
if (!minw.IsAuto)
|
||
{
|
||
size.Width = Math.Max(size.Width, minw.GetActualValue(finalRect.Width));
|
||
}
|
||
if (!minh.IsAuto)
|
||
{
|
||
size.Height = Math.Max(size.Height, minh.GetActualValue(finalRect.Height));
|
||
}
|
||
if (!maxw.IsAuto)
|
||
{
|
||
size.Width = Math.Min(size.Width, maxw.GetActualValue(finalRect.Width));
|
||
}
|
||
if (!maxh.IsAuto)
|
||
{
|
||
size.Height = Math.Min(size.Height, maxh.GetActualValue(finalRect.Height));
|
||
}
|
||
|
||
|
||
var originX = finalRect.X + l.GetActualValue(finalRect.Width);
|
||
var originY = finalRect.Y + t.GetActualValue(finalRect.Height);
|
||
if (l.IsAuto && !r.IsAuto)
|
||
{
|
||
originX = finalRect.Right - size.Width - r.GetActualValue(finalRect.Width);
|
||
}
|
||
else if (l.IsAuto && r.IsAuto)
|
||
{
|
||
originX = finalRect.Left + (finalRect.Width - size.Width) / 2;
|
||
if (isPanel && size.Width > finalRect.Width)
|
||
{
|
||
originX = finalRect.X;
|
||
}
|
||
}
|
||
if (t.IsAuto && !b.IsAuto)
|
||
{
|
||
originY = finalRect.Bottom - size.Height - b.GetActualValue(finalRect.Height);
|
||
}
|
||
else if (t.IsAuto && b.IsAuto)
|
||
{
|
||
originY = finalRect.Top + (finalRect.Height - size.Height) / 2;
|
||
if (isPanel && size.Height > finalRect.Height)
|
||
{
|
||
originY = finalRect.Y;
|
||
}
|
||
}
|
||
if (UseLayoutRounding)
|
||
{
|
||
originX = (float)Math.Floor(originX * scale) / scale;
|
||
originY = (float)Math.Floor(originY * scale) / scale;
|
||
size.Width = (float)Math.Ceiling(size.Width * scale) / scale;
|
||
size.Height = (float)Math.Ceiling(size.Height * scale) / scale;
|
||
}
|
||
|
||
var offset = new Point(originX, originY);
|
||
VisualOffset = offset;
|
||
if (ActualSize != size)
|
||
{
|
||
ActualSize = size;
|
||
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)
|
||
//{
|
||
// var l = MarginLeft;
|
||
// var t = MarginTop;
|
||
// var r = MarginRight;
|
||
// var b = MarginBottom;
|
||
// var w = Width;
|
||
// var h = Height;
|
||
// var maxw = MaxWidth;
|
||
// var maxh = MaxHeight;
|
||
// var minw = MinWidth;
|
||
// var minh = MinHeight;
|
||
// var margin = new Thickness(
|
||
// l.GetActualValue(finalRect.Width),
|
||
// t.GetActualValue(finalRect.Height),
|
||
// r.GetActualValue(finalRect.Width),
|
||
// b.GetActualValue(finalRect.Height));
|
||
// //var originX = finalRect.X + margin.Left;
|
||
// //var originY = finalRect.Y + margin.Top;
|
||
// //var availableSizeMinusMargins = new Size(
|
||
// // Math.Max(0, finalRect.Width - margin.Left - margin.Right),
|
||
// // Math.Max(0, finalRect.Height - margin.Top - margin.Bottom));
|
||
|
||
// //var size = availableSizeMinusMargins;
|
||
// var scale = Root.Scaling;
|
||
|
||
// //if (Name == "2号")
|
||
// //{
|
||
|
||
// //}
|
||
|
||
// var size = DesiredSize.Deflate(margin);
|
||
// if (!l.IsAuto && !r.IsAuto)
|
||
// {
|
||
// size.Width = Math.Max(finalRect.Width - l.GetActualValue(finalRect.Width) - r.GetActualValue(finalRect.Width), 0);
|
||
// }
|
||
// if (!t.IsAuto && !b.IsAuto)
|
||
// {
|
||
// size.Height = Math.Max(finalRect.Height - t.GetActualValue(finalRect.Height) - b.GetActualValue(finalRect.Height), 0);
|
||
// }
|
||
// if (!w.IsAuto)
|
||
// {
|
||
// size.Width = Math.Max(0, w.GetActualValue(finalRect.Width));
|
||
// }
|
||
// if (!h.IsAuto)
|
||
// {
|
||
// size.Height = Math.Max(0, h.GetActualValue(finalRect.Height));
|
||
// }
|
||
// if (!minw.IsAuto)
|
||
// {
|
||
// size.Width = Math.Max(size.Width, minw.GetActualValue(finalRect.Width));
|
||
// }
|
||
// if (!minh.IsAuto)
|
||
// {
|
||
// size.Height = Math.Max(size.Height, minh.GetActualValue(finalRect.Height));
|
||
// }
|
||
// if (!maxw.IsAuto)
|
||
// {
|
||
// size.Width = Math.Min(size.Width, maxw.GetActualValue(finalRect.Width));
|
||
// }
|
||
// if (!maxh.IsAuto)
|
||
// {
|
||
// size.Height = Math.Min(size.Height, maxh.GetActualValue(finalRect.Height));
|
||
// }
|
||
|
||
// //var s = _previousArrangeResultSize;
|
||
// //if (_previousArrangeFinalSize != size)
|
||
// //{
|
||
// var s = ArrangeOverride(size);
|
||
// // _previousArrangeResultSize = s;
|
||
// // _previousArrangeFinalSize = size;
|
||
// //}
|
||
|
||
// size = new Size(Math.Max(s.Width, size.Width), Math.Max(s.Height, size.Height));
|
||
|
||
// if (!minw.IsAuto)
|
||
// {
|
||
// size.Width = Math.Max(size.Width, minw.GetActualValue(finalRect.Width));
|
||
// }
|
||
// if (!minh.IsAuto)
|
||
// {
|
||
// size.Height = Math.Max(size.Height, minh.GetActualValue(finalRect.Height));
|
||
// }
|
||
// if (!maxw.IsAuto)
|
||
// {
|
||
// size.Width = Math.Min(size.Width, maxw.GetActualValue(finalRect.Width));
|
||
// }
|
||
// if (!maxh.IsAuto)
|
||
// {
|
||
// size.Height = Math.Min(size.Height, maxh.GetActualValue(finalRect.Height));
|
||
// }
|
||
|
||
|
||
// var originX = finalRect.X + l.GetActualValue(finalRect.Width);
|
||
// var originY = finalRect.Y + t.GetActualValue(finalRect.Height);
|
||
// if (l.IsAuto && !r.IsAuto)
|
||
// {
|
||
// originX = finalRect.Right - size.Width - r.GetActualValue(finalRect.Width);
|
||
// }
|
||
// else if (l.IsAuto && r.IsAuto)
|
||
// {
|
||
// originX = finalRect.Left + (finalRect.Width - size.Width) / 2;
|
||
// }
|
||
// if (t.IsAuto && !b.IsAuto)
|
||
// {
|
||
// originY = finalRect.Bottom - size.Height - b.GetActualValue(finalRect.Height);
|
||
// }
|
||
// else if (t.IsAuto && b.IsAuto)
|
||
// {
|
||
// originY = finalRect.Top + (finalRect.Height - size.Height) / 2;
|
||
// }
|
||
// if (UseLayoutRounding)
|
||
// {
|
||
// originX = (float)Math.Floor(originX * scale) / scale;
|
||
// originY = (float)Math.Floor(originY * scale) / scale;
|
||
// size.Width = (float)Math.Ceiling(size.Width * scale) / scale;
|
||
// size.Height = (float)Math.Ceiling(size.Height * scale) / scale;
|
||
// }
|
||
|
||
// //var previousSize = ActualSize;
|
||
// //var previousOffset = VisualOffset;
|
||
// //var bounds = GetHostClipBounds(new Rect(new Point(), previousSize));
|
||
// //if (previousSize != size || previousOffset != new Point(originX, originY))
|
||
// //{
|
||
// var offset = new Point(originX, originY);
|
||
// VisualOffset = offset;
|
||
// ActualSize = size;
|
||
// // if (children != null)
|
||
// // {
|
||
// // foreach (UIElement item in children)
|
||
// // {
|
||
// // var rect = item.previousRenderRect;
|
||
// // rect.Union(item.RenderBounds);
|
||
// // bounds.Union(rect);
|
||
// // //Host.Invalidate(rect);
|
||
// // }
|
||
// // }
|
||
// // bounds.Union(GetHostClipBounds(new Rect(new Point(), size)));
|
||
// // Host.Invalidate(bounds);
|
||
// //}
|
||
|
||
// //var p = Parent;
|
||
// //if (p != null)
|
||
// //{
|
||
// // p.Invalidate();
|
||
// //}
|
||
//}
|
||
/// <summary>
|
||
/// Positions child elements as part of a layout pass.
|
||
/// </summary>
|
||
/// <param name="finalSize">The size available to the control.</param>
|
||
/// <returns>The actual size used.</returns>
|
||
protected virtual Size ArrangeOverride(in Size finalSize)
|
||
{
|
||
var rect = new Rect(0, 0, finalSize.Width, finalSize.Height);
|
||
foreach (UIElement child in Children)
|
||
{
|
||
child.Arrange(rect);
|
||
}
|
||
|
||
return finalSize;
|
||
}
|
||
///// <summary>
|
||
///// 去掉Padding
|
||
///// </summary>
|
||
///// <param name="finalSize"></param>
|
||
///// <returns></returns>
|
||
//protected Rect GetArrangeRect(Size finalSize)
|
||
//{
|
||
// //var rect = new Rect(finalSize);
|
||
// return new Rect(0, 0, finalSize.Width, finalSize.Height);
|
||
//}
|
||
|
||
/// <summary>
|
||
/// Invalidates the measurement of the control and queues a new layout pass.测量
|
||
/// </summary>
|
||
public void InvalidateMeasure()
|
||
{
|
||
if (IsMeasureValid && !IsDisposed)
|
||
{
|
||
//Logger.Verbose(LogArea.Layout, this, "Invalidated measure");
|
||
|
||
IsMeasureValid = false;
|
||
IsArrangeValid = false;
|
||
Root?.InvalidateMeasure(this);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// Invalidates the arrangement of the control and queues a new layout pass.布局
|
||
/// </summary>
|
||
public void InvalidateArrange()
|
||
{
|
||
if (IsArrangeValid && !IsDisposed)
|
||
{
|
||
IsArrangeValid = false;
|
||
//LayoutManager.Instance?.InvalidateArrange(this);
|
||
Root?.InvalidateArrange(this);
|
||
//var parent = Parent;
|
||
//if (parent != null)
|
||
//{
|
||
// parent.Invalidate();
|
||
//}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Tests whether any of a <see cref="Rect"/>'s properties incude nagative values,
|
||
/// a NaN or Infinity.
|
||
/// </summary>
|
||
/// <param name="rect">The rect.</param>
|
||
/// <returns>True if the rect is invalid; otherwise false.</returns>
|
||
private static bool IsInvalidRect(Rect rect)
|
||
{
|
||
return rect.Width < 0 || rect.Height < 0 ||
|
||
float.IsInfinity(rect.X) || float.IsInfinity(rect.Y) ||
|
||
float.IsInfinity(rect.Width) || float.IsInfinity(rect.Height) ||
|
||
float.IsNaN(rect.X) || float.IsNaN(rect.Y) ||
|
||
float.IsNaN(rect.Width) || float.IsNaN(rect.Height);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 坐标转换,将父级坐标通过逆向变换为自己内部坐标
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public virtual Point TransformPointInvert(Point point)
|
||
{
|
||
Matrix m = VisualTransform.Value;
|
||
var op = RenderTransformOrigin;
|
||
Rect rect = GetContentBounds();
|
||
Point p = new Point(point.X - op.X.GetActualValue(rect.Width) - rect.X, point.Y - op.Y.GetActualValue(rect.Height) - rect.Y);
|
||
m.TranslatePrepend(-rect.X, -rect.Y);
|
||
m.Invert();
|
||
m.Translate(op.X.GetActualValue(rect.Width), op.Y.GetActualValue(rect.Height));
|
||
return m.Transform(p);
|
||
}
|
||
/// <summary>
|
||
/// 坐标转换,将自己内部坐标转换成父级坐标
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public virtual Point TransformPoint(Point point)
|
||
{
|
||
Rect rect = this.GetContentBounds();
|
||
Matrix m = Matrix.Identity;
|
||
var op = this.RenderTransformOrigin;
|
||
m.TranslatePrepend(rect.X + op.X.GetActualValue(rect.Width), rect.Y + op.Y.GetActualValue(rect.Height));
|
||
m.Prepend(this.VisualTransform.Value);
|
||
m.TranslatePrepend(-op.X.GetActualValue(rect.Width), -op.Y.GetActualValue(rect.Height));
|
||
return m.Transform(point);
|
||
}
|
||
|
||
private Point TransformPoint(in Point point, in Rect rect, in PointField op)
|
||
{
|
||
Matrix m = Matrix.Identity;
|
||
m.TranslatePrepend(rect.X + op.X.GetActualValue(rect.Width), rect.Y + op.Y.GetActualValue(rect.Height));
|
||
m.Prepend(this.VisualTransform.Value);
|
||
m.TranslatePrepend(-op.X.GetActualValue(rect.Width), -op.Y.GetActualValue(rect.Height));
|
||
return m.Transform(point);
|
||
}
|
||
/// <summary>
|
||
/// 用自己的内部坐标测试内部元素,从最深的后代元素到根(自己)
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public IEnumerable<UIElement> HitTest(Point point)
|
||
{
|
||
List<UIElement> list = new List<UIElement>();
|
||
if (HitTest(point, this, list))
|
||
{
|
||
list.Add(this);
|
||
}
|
||
else
|
||
{
|
||
if (HitTestCore(new Point(point.X + ActualOffset.X, point.Y + ActualOffset.Y)))
|
||
{
|
||
list.Add(this);
|
||
}
|
||
}
|
||
return list;
|
||
}
|
||
|
||
bool HitTest(Point point, UIElement element, List<UIElement> list)
|
||
{
|
||
bool isHit = false;
|
||
for (int i = element.Children.Count - 1; i >= 0; i--)
|
||
{
|
||
var item = element.Children[i];
|
||
if (item.Visibility != Visibility.Collapsed)
|
||
{
|
||
Point l = item.ActualOffset;
|
||
Point r = item.TransformPointInvert(point);
|
||
Point t = new Point(r.X - l.X, r.Y - l.Y);
|
||
|
||
isHit = item.HitTestCore(r);
|
||
if (item.ClipToBounds)//如果是裁剪了,需要先判断自己,再判断子元素
|
||
{
|
||
if (isHit)
|
||
{
|
||
HitTest(t, item, list);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
isHit = (HitTest(t, item, list) || isHit);
|
||
}
|
||
if (isHit)
|
||
{
|
||
list.Add(item);
|
||
}
|
||
}
|
||
}
|
||
return isHit;
|
||
}
|
||
|
||
|
||
public override void Render(DrawingContext dc)
|
||
{
|
||
base.Render(dc);
|
||
if (Site != null)
|
||
{
|
||
if (Site.GetType().GetProperty("ShowBorder") == null || (bool)Site.GetPropretyValue("ShowBorder"))
|
||
{
|
||
var s = ActualSize;
|
||
s.Width = Math.Max(1, s.Width);
|
||
s.Height = Math.Max(1, s.Height);
|
||
ViewFill fill = Color.FromRgb(80, 80, 80);
|
||
using (var sb = fill.CreateBrush(new Rect(0, 0, s.Width, s.Height), Root.RenderScaling))
|
||
{
|
||
var dpi = Root.RenderScaling;
|
||
var str = new Stroke(1);
|
||
str.DashStyle = DashStyles.Dash;
|
||
str.Width = Math.Max(0.1f, (float)Math.Round(dpi * str.Width) / dpi);
|
||
dc.DrawRectangle(sb, str, new Rect(str.Width / 2, str.Width / 2, s.Width - str.Width, s.Height - str.Width));
|
||
}
|
||
}
|
||
}
|
||
var fm = FocusMethod;
|
||
if (fm == NavigationMethod.Directional || fm == NavigationMethod.Tab)
|
||
{
|
||
var s = ActualSize;
|
||
var f = FocusFrameFill;
|
||
var padding = FocusFramePadding;
|
||
if (s.Width > padding.Horizontal && s.Height > padding.Vertical && f != null)
|
||
{
|
||
using (var sb = f.CreateBrush(new Rect(0, 0, s.Width, s.Height), Root.RenderScaling))
|
||
{
|
||
var dpi = Root.RenderScaling;
|
||
var str = FocusFrameStroke;
|
||
str.Width = (float)Math.Round(dpi * str.Width) / dpi;
|
||
dc.DrawRectangle(sb, str, new Rect(padding.Left, padding.Top, s.Width - padding.Horizontal, s.Height - padding.Vertical));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取相对于父级的正矩形剪辑区域
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public Rect GetClipBounds()
|
||
{
|
||
Rect r = GetContentBounds();
|
||
if (VisualTransform == Transform.Identity)
|
||
{
|
||
return r;
|
||
}
|
||
Point lt = new Point();
|
||
Point tr = new Point(r.Width, 0);
|
||
Point lb = new Point(0, r.Height);
|
||
Point rb = new Point(r.Width, r.Height);
|
||
var op = RenderTransformOrigin;
|
||
//Rect r = GetContentBounds();
|
||
lt = TransformPoint(lt, r, op);
|
||
tr = TransformPoint(tr, r, op);
|
||
lb = TransformPoint(lb, r, op);
|
||
rb = TransformPoint(rb, r, op);
|
||
|
||
float minX = Math.Min(Math.Min(Math.Min(lt.X, tr.X), lb.X), rb.X);
|
||
float minY = Math.Min(Math.Min(Math.Min(lt.Y, tr.Y), lb.Y), rb.Y);
|
||
float maxX = Math.Max(Math.Max(Math.Max(lt.X, tr.X), lb.X), rb.X);
|
||
float maxY = Math.Max(Math.Max(Math.Max(lt.Y, tr.Y), lb.Y), rb.Y);
|
||
return new Rect(minX, minY, maxX - minX, maxY - minY);
|
||
}
|
||
/// <summary>
|
||
/// 获取内部相对于父级的正矩形剪辑区域
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public Rect GetClipBounds(in Rect rect)
|
||
{
|
||
Rect r = GetContentBounds();
|
||
if (VisualTransform == Transform.Identity)
|
||
{
|
||
return new Rect(r.X + rect.X, rect.Y + r.Y, rect.Width, rect.Height);
|
||
}
|
||
Point lt = new Point(rect.Left, rect.Top);
|
||
Point tr = new Point(rect.Left + rect.Width, rect.Top);
|
||
Point lb = new Point(rect.Left, rect.Top + rect.Height);
|
||
Point rb = new Point(rect.Left + rect.Width, rect.Top + rect.Height);
|
||
var op = RenderTransformOrigin;
|
||
lt = TransformPoint(lt, r, op);
|
||
tr = TransformPoint(tr, r, op);
|
||
lb = TransformPoint(lb, r, op);
|
||
rb = TransformPoint(rb, r, op);
|
||
|
||
float minX = Math.Min(Math.Min(Math.Min(lt.X, tr.X), lb.X), rb.X);
|
||
float minY = Math.Min(Math.Min(Math.Min(lt.Y, tr.Y), lb.Y), rb.Y);
|
||
float maxX = Math.Max(Math.Max(Math.Max(lt.X, tr.X), lb.X), rb.X);
|
||
float maxY = Math.Max(Math.Max(Math.Max(lt.Y, tr.Y), lb.Y), rb.Y);
|
||
return new Rect(minX, minY, maxX - minX, maxY - minY);
|
||
}
|
||
|
||
public override Rect GetContentBounds()
|
||
{
|
||
if (IsRoot)
|
||
{
|
||
//Size s = Root.Size;
|
||
return new Rect(new Point(), Root.ActualSize);
|
||
}
|
||
//return new Rect(VisualOffset, new Size(Width, Height));
|
||
return contentBounds;
|
||
//return new Rect(VisualOffset, ActualSize);
|
||
}
|
||
//private float GetLayoutScale()
|
||
//{
|
||
// return Root.Scaling;
|
||
//}
|
||
|
||
//bool drawFocusRect = false;
|
||
//private bool DrawFocusRect
|
||
//{
|
||
// get { return drawFocusRect; }
|
||
// set
|
||
// {
|
||
// if (drawFocusRect != value)
|
||
// {
|
||
// drawFocusRect = value;
|
||
// Invalidate();
|
||
// }
|
||
// }
|
||
//}
|
||
public void Invoke(Action action)
|
||
{
|
||
if (!this.IsDisposed)
|
||
{
|
||
Threading.Dispatcher.MainThread.Invoke(action);
|
||
}
|
||
}
|
||
//public void Invoke(SendOrPostCallback action, object data)
|
||
//{
|
||
// if (!this.IsDisposed)
|
||
// {
|
||
// Threading.Dispatcher.MainThread.Invoke(action, data);
|
||
// }
|
||
//}
|
||
|
||
public void BeginInvoke(Action action)
|
||
{
|
||
if (!this.IsDisposed)
|
||
{
|
||
Threading.Dispatcher.MainThread.BeginInvoke(action);
|
||
}
|
||
}
|
||
public void BeginInvoke(SendOrPostCallback action, object data)
|
||
{
|
||
if (!this.IsDisposed)
|
||
{
|
||
Threading.Dispatcher.MainThread.BeginInvoke(action, data);
|
||
}
|
||
}
|
||
|
||
public bool Focus(NavigationMethod m)
|
||
{
|
||
FocusMethod = m;
|
||
IsFocused = true;
|
||
//System.Diagnostics.Debug.WriteLine(this);
|
||
var host = Root;
|
||
if (Visibility != Visibility.Visible || !IsEnabled || host == null || !host.CanActivate)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
host.InputManager.KeyboardDevice.SetFocus(this);
|
||
IsKeyboardFocused = true;
|
||
IsKeyboardFocusWithin = true;
|
||
//if (m == NavigationMethod.Tab || m == NavigationMethod.Directional)
|
||
//{
|
||
//}
|
||
var e = new GotFocusEventArgs(this) { NavigationMethod = m };
|
||
OnGotFocus(e);
|
||
InnerFocus(e);
|
||
return true;
|
||
}
|
||
public bool Focus()
|
||
{
|
||
return Focus(NavigationMethod.Unspecified);
|
||
}
|
||
|
||
private void InnerFocus(GotFocusEventArgs e)
|
||
{
|
||
if (e.OriginalSource != this)
|
||
{
|
||
IsKeyboardFocusWithin = true;
|
||
IsKeyboardFocused = false;
|
||
IsFocused = false;
|
||
OnGotFocus(e);
|
||
}
|
||
//else
|
||
//{
|
||
// IsFocused = true;
|
||
// IsKeyboardFocused = true;
|
||
//}
|
||
var p = Parent;
|
||
if (p != null)
|
||
{
|
||
if (!e.Handled)
|
||
{
|
||
p.InnerFocus(e);
|
||
}
|
||
foreach (UIElement item in p.Children)
|
||
{
|
||
if (item != this)
|
||
{//同级的其他元素失去焦点
|
||
item.InnerLostFocus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
internal void InnerLostFocus()
|
||
{
|
||
if (!IsDisposed && IsKeyboardFocusWithin)
|
||
{
|
||
IsKeyboardFocused = false;
|
||
IsKeyboardFocusWithin = false;
|
||
IsFocused = false;
|
||
FocusMethod = null;
|
||
OnLostFocus(new RoutedEventArgs(this));
|
||
foreach (UIElement item in Children)
|
||
{//子元素都失去焦点
|
||
item.InnerLostFocus();
|
||
}
|
||
}
|
||
}
|
||
|
||
UIElementCollection children;
|
||
/// <summary>
|
||
/// 子级,一般自定义组件的时候使用
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
internal protected UIElementCollection Children
|
||
{
|
||
get
|
||
{
|
||
if (children == null)
|
||
{
|
||
children = new UIElementCollection(this);
|
||
}
|
||
return children;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取子元素
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
|
||
#if Net4
|
||
public IList<UIElement> GetChildren()
|
||
#else
|
||
public IReadOnlyList<UIElement> GetChildren()
|
||
#endif
|
||
{
|
||
return Children;
|
||
}
|
||
/// <summary>
|
||
/// 当添加触发器时并且触发器有设置动画,如果满足条件是否播放动画
|
||
/// </summary>
|
||
[Description("当添加触发器时并且触发器有设置动画,如果满足条件是否播放动画")]
|
||
public bool PlayAnimationOnAddTrigger
|
||
{
|
||
get { return GetValue<bool>(35); }
|
||
set { SetValue(value, 35); }
|
||
}
|
||
|
||
internal Triggers triggers;
|
||
/// <summary>
|
||
/// 触发器集合
|
||
/// </summary>
|
||
[NotCpfProperty]
|
||
[Category("设计")]
|
||
[Description("设置触发器")]
|
||
public Triggers Triggers
|
||
{
|
||
get
|
||
{
|
||
if (triggers == null)
|
||
{
|
||
triggers = new Triggers();
|
||
triggers.CollectionChanged += (s, e) =>
|
||
{
|
||
Trigger n = e.NewItem;
|
||
var o = e.OldItem;
|
||
switch (e.Action)
|
||
{
|
||
case CollectionChangedAction.Add:
|
||
if (!string.IsNullOrEmpty(n.Property) && n.Condition(this))
|
||
{
|
||
if (n.TargetRelation != null && n.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in n.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(n, item, true, true);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(n, this, true, true);
|
||
}
|
||
}
|
||
break;
|
||
case CollectionChangedAction.Remove:
|
||
//foreach (var setter in e.Item.Setters)
|
||
//{
|
||
// ClearTriggerValue(e.Item, setter.Key);
|
||
//}
|
||
if (o.TargetRelation != null && o.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in o.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(o, item, false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(o, this, false);
|
||
}
|
||
break;
|
||
case CollectionChangedAction.Replace:
|
||
if (!string.IsNullOrEmpty(n.Property) && n.Condition(this))
|
||
{
|
||
if (n.TargetRelation != null && n.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in n.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(n, item, true, true);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(n, this, true, true);
|
||
}
|
||
}
|
||
if (o.TargetRelation != null && o.TargetRelation != Relation.Me)
|
||
{
|
||
foreach (var item in o.TargetRelation.Query(this))
|
||
{
|
||
SetTrigger(o, item, false);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SetTrigger(o, this, false);
|
||
}
|
||
break;
|
||
}
|
||
};
|
||
}
|
||
return triggers;
|
||
}
|
||
}
|
||
|
||
[NotCpfProperty]
|
||
[Browsable(false)]
|
||
public ISite Site
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
/// <summary>
|
||
/// 是否处在设计模式
|
||
/// </summary>
|
||
[UIPropertyMetadata(false, true)]
|
||
[Browsable(false)]
|
||
public bool DesignMode
|
||
{
|
||
get
|
||
{
|
||
return (bool)GetValue();
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 是否是设计模式下的根元素
|
||
/// </summary>
|
||
[Browsable(false)]
|
||
public bool IsRootInDesignMode
|
||
{
|
||
get
|
||
{
|
||
return (bool)GetValue();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将指定工作区点的位置计算成屏幕坐标。像素坐标
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public override Point PointToScreen(Point point)
|
||
{
|
||
var p = this;
|
||
while (p != null)
|
||
{
|
||
point = p.TransformPoint(point);
|
||
p = p.Parent;
|
||
}
|
||
point = Root.PointToScreen(point);
|
||
return point;
|
||
}
|
||
/// <summary>
|
||
/// 将指定工作区点的位置计算成相对View的位置
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public Point PointToView(Point point)
|
||
{
|
||
var p = this;
|
||
while (p != null)
|
||
{
|
||
point = p.TransformPoint(point);
|
||
p = p.Parent;
|
||
}
|
||
return point;
|
||
}
|
||
/// <summary>
|
||
/// 将指定屏幕点的像素位置计算成工作区坐标。
|
||
/// </summary>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public Point PointToClient(Point point)
|
||
{
|
||
point = Root.ViewImpl.PointToClient(point);
|
||
var p = this;
|
||
List<UIElement> list = new List<UIElement>();
|
||
while (p != null)
|
||
{
|
||
list.Add(p);
|
||
p = p.Parent;
|
||
}
|
||
for (int i = list.Count - 1; i >= 0; i--)
|
||
{
|
||
var item = list[i];
|
||
Point l = new Point();
|
||
if (!item.IsRoot)
|
||
{
|
||
l = item.ActualOffset;
|
||
}
|
||
Point r = item.TransformPointInvert(point);
|
||
point = new Point(r.X - l.X, r.Y - l.Y);
|
||
}
|
||
return point;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用到元素上的类名,多个类用,分割
|
||
/// </summary>
|
||
[Description("应用到元素上的类名,多个类用,分割")]
|
||
[Category("设计")]
|
||
[NotCpfProperty]
|
||
public Classes Classes
|
||
{
|
||
get
|
||
{
|
||
if (classes == null)
|
||
{
|
||
classes = new Classes();
|
||
}
|
||
return classes;
|
||
}
|
||
set
|
||
{
|
||
classes = value;
|
||
}
|
||
}
|
||
|
||
protected internal override void OnAddTriggerDescribe(string property, TriggerDescribe trigger)
|
||
{
|
||
var t = new Trigger { Animation = trigger.Animation, AnimationDuration = trigger.AnimationDuration, AnimationEndBehavior = trigger.AnimationEndBehavior, AnimationIterationCount = trigger.AnimationIterationCount, PropertyConditions = trigger.PropertyConditions, TargetRelation = trigger.TargetRelation, Property = property };
|
||
if (trigger.Setters != null && trigger.Setters.Length > 0)
|
||
{
|
||
foreach (var item in trigger.Setters)
|
||
{
|
||
t.Setters.Add(item.Item1, item.Item2);
|
||
}
|
||
}
|
||
if (t.PropertyConditions == null)
|
||
{
|
||
t.PropertyConditions = t.DefaultPropertyConditions;
|
||
}
|
||
Triggers.Add(t);
|
||
}
|
||
|
||
//Styles styles;
|
||
|
||
protected override void Dispose(bool disposing)
|
||
{
|
||
if (disposing)
|
||
{
|
||
PresenterFor = null;
|
||
if (toolTipElement)
|
||
{
|
||
if (ToolTipUIElement == toolTipElement)
|
||
{
|
||
ToolTipHost.Visibility = Visibility.Collapsed;
|
||
ToolTipUIElement = null;
|
||
}
|
||
toolTipElement.Dispose();
|
||
}
|
||
if (triggers != null)
|
||
{
|
||
triggers.Clear();
|
||
}
|
||
if (notifyList != null)
|
||
{
|
||
foreach (var item in notifyList)
|
||
{
|
||
item.Key.PropertyChanged -= Notify_PropertyChanged;
|
||
}
|
||
}
|
||
if (children != null)
|
||
{
|
||
var c = children.Count;
|
||
//for (int i = 0; i < c; i++)
|
||
//{
|
||
// var cc = children[0];
|
||
// cc.Dispose();
|
||
//}
|
||
for (int i = c - 1; i >= 0; i--)
|
||
{
|
||
children[i].Dispose();
|
||
}
|
||
}
|
||
var p = Parent;
|
||
if (p != null)
|
||
{
|
||
p.children.Remove(this);
|
||
}
|
||
}
|
||
this.RaiseEvent(EventArgs.Empty, nameof(Disposed));
|
||
base.Dispose(disposing);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 查询所有内部元素,包含所有层
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <returns></returns>
|
||
public IEnumerable<T> Find<T>() where T : UIElement
|
||
{
|
||
if (children == null)
|
||
{
|
||
yield break;
|
||
}
|
||
foreach (UIElement item in Children)
|
||
{
|
||
if (item is T)
|
||
{
|
||
yield return (T)item;
|
||
}
|
||
foreach (var c in item.Find<T>())
|
||
{
|
||
yield return c;
|
||
}
|
||
}
|
||
}
|
||
|
||
internal void LoadStyle()
|
||
{
|
||
var host = Root;
|
||
//if (host.StyleSheet != null)
|
||
//{
|
||
// foreach (var item in host.StyleSheet.StyleRules)
|
||
// {
|
||
// //host.SetStyle(this, item);
|
||
// }
|
||
//}
|
||
if (host.Styles.Count > 0)
|
||
{
|
||
host.Styles.Update();
|
||
host.SetStyle(this);
|
||
}
|
||
if (afterStyle != null)
|
||
{
|
||
if (host.IsInitialized)
|
||
{
|
||
afterStyle.Method.FastInvoke(afterStyle.Target, this);
|
||
}
|
||
else
|
||
{
|
||
if (host.afterStyles == null)
|
||
{
|
||
host.afterStyles = new List<(Delegate, UIElement)>();
|
||
}
|
||
host.afterStyles.Add((afterStyle, this));
|
||
}
|
||
}
|
||
}
|
||
[NotCpfProperty]
|
||
internal bool loadStyle { set { SetFlag(CoreFlags.loadStyle, value); } get { return GetFlag(CoreFlags.loadStyle); } }// = true;
|
||
void AttachedToVisualTree()
|
||
{
|
||
if (loadStyle)
|
||
{
|
||
Root.OnElementInitialize(this);
|
||
}
|
||
var host = Root;
|
||
if (bindings != null)
|
||
{
|
||
foreach (var item in bindings.binds)
|
||
{
|
||
foreach (var binding in item.Value)
|
||
{
|
||
if (binding.SourceElementLayer.HasValue)
|
||
{
|
||
UIElement obj = this;
|
||
for (int i = 1; i < binding.SourceElementLayer.Value + 1; i++)
|
||
{
|
||
obj = obj.Parent;
|
||
}
|
||
if (binding.Source == null)
|
||
{
|
||
binding.Source = new WeakReference(obj);
|
||
}
|
||
var bindingMode = binding.BindingMode;
|
||
if (bindingMode == BindingMode.OneWay || bindingMode == BindingMode.TwoWay)
|
||
{
|
||
//((INotifyPropertyChanged)obj).PropertyChanged += binding.PropertyChanged;
|
||
binding.RegisterPropertyChanged((INotifyPropertyChanged)obj);
|
||
binding.SourceToTarget();
|
||
}
|
||
else if (bindingMode == BindingMode.OneWayToSource)
|
||
{
|
||
binding.TargetToSource();
|
||
}
|
||
else if (bindingMode == BindingMode.OneTime)
|
||
{
|
||
binding.SourceToTarget();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (inheritsPropertyName != null)
|
||
{
|
||
foreach (var item in inheritsPropertyName)
|
||
{
|
||
if (!HasLocalOrStyleValue(item, out var attribute))
|
||
{
|
||
var p = Parent;
|
||
while (p != null)
|
||
{
|
||
if (p.inheritsPropertyName != null)
|
||
{
|
||
if (p.inheritsPropertyName.Contains(item))
|
||
{
|
||
if (p.inheritsValues.TryGetValue(item, out InheritsValue v))
|
||
{
|
||
var old = GetValue(item);
|
||
inheritsValues.Remove(item);
|
||
inheritsValues.Add(item, v);
|
||
if (!old.Equal(v.Value))
|
||
{
|
||
//OnPropertyChanged(item, old, v.Value, GetPropertyMetadata(item));
|
||
OnPropertyChanged(item, old, v.Value, attribute);
|
||
}
|
||
break;
|
||
}
|
||
else if (p.HasLocalOrStyleValue(item, out var pa))
|
||
{
|
||
var value = p.GetValue(item);
|
||
var old = GetValue(item);
|
||
inheritsValues.Remove(item);
|
||
v = new InheritsValue { Value = value, ValueForm = ValueFrom.Property };
|
||
inheritsValues.Add(item, v);
|
||
if (!old.Equal(v.Value))
|
||
{
|
||
//OnPropertyChanged(item, old, v.Value, GetPropertyMetadata(item));
|
||
OnPropertyChanged(item, old, v.Value, attribute);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (p.breakInheritsPropertyName != null && p.breakInheritsPropertyName.Contains(item))
|
||
{
|
||
break;
|
||
}
|
||
p = p.Parent;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (children != null)
|
||
{
|
||
foreach (UIElement item in children)
|
||
{
|
||
item.Root = host;
|
||
}
|
||
}
|
||
OnAttachedToVisualTree();
|
||
if (children != null)
|
||
{
|
||
foreach (UIElement item in children)
|
||
{
|
||
item.AttachedToVisualTree();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Called when the control is added to a visual tree.
|
||
/// </summary>
|
||
protected virtual void OnAttachedToVisualTree()
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Called when the control is removed from a visual tree.
|
||
/// </summary>
|
||
protected virtual void OnDetachedFromVisualTree()
|
||
{
|
||
//if (this is Control control && control.IsInitialized)
|
||
//{
|
||
// Root.OnElementFinalize(this);
|
||
//}
|
||
//else
|
||
//{
|
||
// Root.OnElementFinalize(this);
|
||
//}
|
||
if (toolTipElement)
|
||
{
|
||
if (ToolTipUIElement == toolTipElement)
|
||
{
|
||
ToolTipHost.Visibility = Visibility.Collapsed;
|
||
ToolTipUIElement = null;
|
||
}
|
||
}
|
||
if (inheritsPropertyName != null && !IsDisposing)
|
||
{
|
||
foreach (var item in inheritsValues.ToArray())
|
||
{
|
||
if (!HasLocalOrStyleValue(item.Key, out var attribute))
|
||
{
|
||
var old = GetValue(item.Key);
|
||
//if (inheritsValues.ContainsKey(item))
|
||
//{
|
||
inheritsValues.Remove(item.Key);
|
||
//}
|
||
var v = GetValue(item.Key);
|
||
if (!old.Equal(v))
|
||
{
|
||
//OnPropertyChanged(item.Key, old, v, GetPropertyMetadata(item.Key));
|
||
OnPropertyChanged(item.Key, old, v, attribute);
|
||
}
|
||
}
|
||
}
|
||
//inheritsValues.Clear();
|
||
}
|
||
//var name = Name;
|
||
//if (!string.IsNullOrWhiteSpace(name))
|
||
//{
|
||
// var r = Root;
|
||
// if (r.nameDic.TryGetValue(name, out UIElement e))
|
||
// {
|
||
// if (e == this)
|
||
// {
|
||
// r.nameDic.Remove(name);
|
||
// }
|
||
// }
|
||
//}
|
||
IsArrangeValid = false;
|
||
if (children != null)
|
||
{
|
||
foreach (UIElement item in children)
|
||
{
|
||
item.OnDetachedFromVisualTree();
|
||
item.Root = null;
|
||
}
|
||
}
|
||
if (triggers != null && !IsDisposing)
|
||
{
|
||
foreach (var item in triggers.Where(a => a.Style != null).ToArray())
|
||
{
|
||
triggers.Remove(item);
|
||
}
|
||
}
|
||
if (bindings != null)
|
||
{
|
||
foreach (var item in bindings.binds)
|
||
{
|
||
foreach (var binding in item.Value)
|
||
{
|
||
if (binding.SourceElementLayer.HasValue && binding.Source != null && binding.Source.IsAlive)
|
||
{
|
||
//((INotifyPropertyChanged)binding.Source.Target).PropertyChanged -= binding.PropertyChanged;
|
||
binding.CancellationPropertyChanged((INotifyPropertyChanged)binding.Source.Target);
|
||
binding.Source = null;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
ClearStyleValues();
|
||
//if (commands != null)
|
||
//{
|
||
// foreach (var item in commands.commands)
|
||
// {
|
||
// foreach (var command in item.Value)
|
||
// {
|
||
// if (command.SourceElementLayer.HasValue)
|
||
// {
|
||
// command.Target = null;
|
||
// }
|
||
// }
|
||
// }
|
||
//}
|
||
}
|
||
|
||
internal void RaiseUIElementAdded(UIElement child)
|
||
{
|
||
//if (child.ZIndex != 0)
|
||
//{
|
||
// //needSortZIndex = true;
|
||
// children.InvalidateZIndex();
|
||
//}
|
||
if (child.IsRoot)
|
||
{
|
||
throw new Exception("根元素不能作为子元素嵌套");
|
||
}
|
||
if (child.IsDisposed)
|
||
{
|
||
throw new Exception("被释放了的元素不能再添加使用");
|
||
}
|
||
child.Root = Root;
|
||
if (Root != null)
|
||
{
|
||
child.IsMeasureValid = false;
|
||
child.AttachedToVisualTree();
|
||
}
|
||
viewRenderRect = true;
|
||
InvalidateMeasure();
|
||
OnUIElementAdded(new UIElementAddedEventArgs(child, this));
|
||
}
|
||
|
||
protected virtual void OnUIElementAdded(UIElementAddedEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, "UIElementAdded");
|
||
}
|
||
//public static readonly RoutedEvent EventUIElementAdded = new RoutedEvent("UIElementAdded", UIElementType, typeof(EventHandler<UIElementAddedEventArgs>));
|
||
/// <summary>
|
||
/// 添加可视化对象的时候
|
||
/// </summary>
|
||
public virtual event EventHandler<UIElementAddedEventArgs> UIElementAdded
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
internal void RaiseUIElementRemoved(UIElement child)
|
||
{
|
||
if (child.Root != null)
|
||
{
|
||
child.OnDetachedFromVisualTree();
|
||
child.Root = null;
|
||
}
|
||
|
||
if (!IsDisposed)
|
||
{
|
||
viewRenderRect = true;
|
||
InvalidateMeasure();
|
||
}
|
||
OnUIElementRemoved(new UIElementRemovedEventArgs(child, this));
|
||
if (child.needDispose)
|
||
{
|
||
child.Dispose();
|
||
}
|
||
}
|
||
protected virtual void OnUIElementRemoved(UIElementRemovedEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, "UIElementRemoved");
|
||
}
|
||
//public static readonly RoutedEvent EventUIElementRemoved = new RoutedEvent("UIElementRemoved", UIElementType, typeof(EventHandler<UIElementRemovedEventArgs>));
|
||
/// <summary>
|
||
/// 移除可视化对象的时候
|
||
/// </summary>
|
||
public virtual event EventHandler<UIElementRemovedEventArgs> UIElementRemoved
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
public virtual event EventHandler DesiredSizeChanged
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnPreviewMouseDown(MouseButtonEventArgs e)
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine("OnPreviewMouseDown" + this);
|
||
this.RaiseEvent(e, nameof(PreviewMouseDown));
|
||
}
|
||
|
||
public virtual event EventHandler<MouseButtonEventArgs> PreviewMouseDown
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnPreviewMouseUp(MouseButtonEventArgs e)
|
||
{
|
||
//System.Diagnostics.Debug.WriteLine("OnPreviewMouseUp" + this + e.OriginalSource);
|
||
this.RaiseEvent(e, nameof(PreviewMouseUp));
|
||
}
|
||
|
||
public virtual event EventHandler<MouseButtonEventArgs> PreviewMouseUp
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnMouseDown(MouseButtonEventArgs e)
|
||
{
|
||
//if (e.MouseButton == MouseButton.Left)
|
||
//{
|
||
// IsMouseLeftButtonDown = true;
|
||
//}
|
||
//System.Diagnostics.Debug.WriteLine(e.OriginalSource);
|
||
this.RaiseEvent(e, nameof(MouseDown));
|
||
}
|
||
|
||
public virtual event EventHandler<MouseButtonEventArgs> MouseDown
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnMouseUp(MouseButtonEventArgs e)
|
||
{
|
||
//if (e.MouseButton == MouseButton.Left)
|
||
//{
|
||
// IsMouseLeftButtonDown = false;
|
||
//}
|
||
this.RaiseEvent(e, nameof(MouseUp));
|
||
if (e.MouseButton == MouseButton.Right && !e.Handled)
|
||
{
|
||
var cm = ContextMenu;
|
||
if (cm != null)
|
||
{
|
||
cm.DataContext = DataContext;
|
||
cm.CommandContext = CommandContext;
|
||
cm.PlacementTarget = this;
|
||
cm.IsOpen = true;
|
||
}
|
||
}
|
||
}
|
||
//public static readonly RoutedEvent MouseUpEvent = new RoutedEvent("MouseUp", UIElementType, MouseEventType);
|
||
public virtual event EventHandler<MouseButtonEventArgs> MouseUp
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnDoubleClick(RoutedEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(DoubleClick));
|
||
}
|
||
|
||
public virtual event EventHandler<RoutedEventArgs> DoubleClick
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnMouseMove(MouseEventArgs e)
|
||
{
|
||
if (e.OriginalSource == this)
|
||
{
|
||
Root.SetCursor(Cursor);
|
||
}
|
||
this.RaiseEvent(e, nameof(MouseMove));
|
||
}
|
||
//public static readonly RoutedEvent MouseMoveEvent = new RoutedEvent("MouseMove", UIElementType, MouseEventType);
|
||
public virtual event EventHandler<MouseEventArgs> MouseMove
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnMouseEnter(MouseEventArgs e)
|
||
{
|
||
if (toolTipElement)
|
||
{
|
||
var re = new RoutedEventArgs(this);
|
||
RaiseEvent(re, nameof(ToolTipOpening));
|
||
if (!re.Handled)
|
||
{
|
||
ToolTipHost.Width = FloatField.Auto;
|
||
ToolTipHost.Height = FloatField.Auto;
|
||
ShowTip(Root, toolTipElement);
|
||
}
|
||
}
|
||
IsMouseOver = true;
|
||
this.RaiseEvent(e, nameof(MouseEnter));
|
||
}
|
||
//public static readonly RoutedEvent MouseEnterEvent = new RoutedEvent("MouseEnter", UIElementType, MouseEventType);
|
||
public virtual event EventHandler<MouseEventArgs> MouseEnter
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnMouseLeave(MouseEventArgs e)
|
||
{
|
||
if (toolTipElement)
|
||
{
|
||
if (ToolTipUIElement == toolTipElement)
|
||
{
|
||
ToolTipHost.Visibility = Visibility.Collapsed;
|
||
if (!CPF.Platform.Application.DisablePopupClose)
|
||
{
|
||
ToolTipUIElement = null;
|
||
}
|
||
}
|
||
}
|
||
IsMouseOver = false;
|
||
this.RaiseEvent(e, nameof(MouseLeave));
|
||
}
|
||
|
||
public virtual event EventHandler<MouseEventArgs> MouseLeave
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
//public virtual event EventHandler<TouchEventArgs> TouchLeave
|
||
//{
|
||
// add { AddHandler(value); }
|
||
// remove { RemoveHandler(value); }
|
||
//}
|
||
|
||
//protected virtual void OnTouchLeave(TouchEventArgs e)
|
||
//{
|
||
// IsMouseOver = false;
|
||
// //Debug.WriteLine("TouchLeave" + this + e.Position);
|
||
// this.RaiseEvent(e, nameof(TouchLeave));
|
||
//}
|
||
|
||
//public virtual event EventHandler<TouchEventArgs> TouchEnter
|
||
//{
|
||
// add { AddHandler(value); }
|
||
// remove { RemoveHandler(value); }
|
||
//}
|
||
|
||
//protected virtual void OnTouchEnter(TouchEventArgs e)
|
||
//{
|
||
// IsMouseOver = true;
|
||
// //Debug.WriteLine("TouchEnter" + this + e.Position);
|
||
// this.RaiseEvent(e, nameof(TouchEnter));
|
||
//}
|
||
|
||
public virtual event EventHandler<TouchEventArgs> TouchUp
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnTouchUp(TouchEventArgs e)
|
||
{
|
||
//Debug.WriteLine("TouchUp" + this + e.Position);
|
||
this.RaiseEvent(e, nameof(TouchUp));
|
||
}
|
||
|
||
public virtual event EventHandler<TouchEventArgs> TouchDown
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnTouchDown(TouchEventArgs e)
|
||
{
|
||
//Debug.WriteLine("TouchDown" + this + e.Position);
|
||
this.RaiseEvent(e, nameof(TouchDown));
|
||
}
|
||
|
||
|
||
public virtual event EventHandler<TouchEventArgs> TouchMove
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnTouchMove(TouchEventArgs e)
|
||
{
|
||
//Debug.WriteLine("TouchMove" + this + e.Position);
|
||
this.RaiseEvent(e, nameof(TouchMove));
|
||
}
|
||
|
||
//public virtual event EventHandler<TouchEventArgs> ManipulationStarted
|
||
//{
|
||
// add { AddHandler(value); }
|
||
// remove { RemoveHandler(value); }
|
||
//}
|
||
|
||
//protected virtual void OnManipulationStarted(TouchEventArgs e)
|
||
//{
|
||
// this.RaiseEvent(e, nameof(ManipulationStarted));
|
||
//}
|
||
protected virtual void OnMouseWheel(MouseWheelEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(MouseWheel));
|
||
}
|
||
|
||
public virtual event EventHandler<MouseWheelEventArgs> MouseWheel
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnKeyDown(KeyEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(KeyDown));
|
||
}
|
||
|
||
public virtual event EventHandler<KeyEventArgs> KeyDown
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnKeyUp(KeyEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(KeyUp));
|
||
}
|
||
//public static readonly RoutedEvent KeyUpEvent = new RoutedEvent("KeyUp", UIElementType, KeyEventType);
|
||
public virtual event EventHandler<KeyEventArgs> KeyUp
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnTextInput(TextInputEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(TextInput));
|
||
}
|
||
public virtual event EventHandler<TextInputEventArgs> TextInput
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
protected virtual void OnGotFocus(GotFocusEventArgs e)
|
||
{
|
||
this.RaiseEvent(e, nameof(GotFocus));
|
||
}
|
||
//public static readonly RoutedEvent GotFocusEvent = new RoutedEvent("GotFocus", UIElementType, typeof(EventHandler<GotFocusEventArgs>));
|
||
public virtual event EventHandler<GotFocusEventArgs> GotFocus
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnLostFocus(RoutedEventArgs e)
|
||
{
|
||
RaiseEvent(e, nameof(LostFocus));
|
||
}
|
||
//public static readonly RoutedEvent LostFocusEvent = new RoutedEvent("LostFocus", UIElementType, typeof(EventHandler<RoutedEventArgs>));
|
||
public virtual event EventHandler<RoutedEventArgs> LostFocus
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
|
||
protected virtual void OnLayoutUpdated()
|
||
{
|
||
this.RaiseEvent(new RoutedEventArgs(this), nameof(LayoutUpdated));
|
||
}
|
||
/// <summary>
|
||
/// 捕获鼠标,只有鼠标在元素范围内按下,而且IsEnabled为TRUE的时候才能捕获。当对象已捕获鼠标后,它接收鼠标输入,不论鼠标指针是否在其边界区域。 通常只有在执行模拟拖动操作时才捕获鼠标。 若要释放鼠标捕获,请对具有捕获的对象调用 ReleaseMouseCapture 方法。
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public bool CaptureMouse()
|
||
{
|
||
var host = Root;
|
||
if (IsEnabled && host != null)
|
||
{
|
||
host.InputManager.MouseDevice.Capture(this);
|
||
IsMouseCaptured = true;
|
||
OnCaptureMouse();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
protected virtual void OnCaptureMouse()
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// ReleaseMouseCapture 方法对于已通过使用 CaptureMouse 方法捕获鼠标的对象禁用鼠标捕获。 当对象已捕获鼠标后,它接收鼠标输入,不论鼠标指针是否在其边界区域。 对不具有鼠标捕获的对象调用 ReleaseMouseCapture 无效。
|
||
/// </summary>
|
||
public void ReleaseMouseCapture()
|
||
{
|
||
var host = Root;
|
||
if (host != null)
|
||
{
|
||
host.InputManager.MouseDevice.Capture(null);
|
||
}
|
||
SetReleaseMouseCapture();
|
||
}
|
||
|
||
internal void SetReleaseMouseCapture()
|
||
{
|
||
if (IsMouseCaptured)
|
||
{
|
||
IsMouseCaptured = false;
|
||
OnReleaseMouseCapture();
|
||
}
|
||
}
|
||
|
||
protected virtual void OnReleaseMouseCapture()
|
||
{
|
||
|
||
}
|
||
|
||
//public static readonly RoutedEvent LayoutUpdatedEvent = new RoutedEvent("LayoutUpdated", UIElementType, typeof(EventHandler<RoutedEventArgs>));
|
||
public virtual event EventHandler<RoutedEventArgs> LayoutUpdated
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
public event EventHandler Disposed
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
//public event EventHandler<RoutedEventArgs> ToolTipClosing
|
||
//{
|
||
// add { AddHandler(value); }
|
||
// remove { RemoveHandler(value); }
|
||
//}
|
||
public event EventHandler<RoutedEventArgs> ToolTipOpening
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnDragEnter(DragEventArgs e)
|
||
{
|
||
IsDragOver = true;
|
||
//System.Diagnostics.Debug.WriteLine(this + " " + e.DragEffects);
|
||
RaiseEvent(e, nameof(DragEnter));
|
||
}
|
||
public event EventHandler<DragEventArgs> DragEnter
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnDragLeave(EventArgs e)
|
||
{
|
||
IsDragOver = false;
|
||
RaiseEvent(e, nameof(DragLeave));
|
||
}
|
||
public event EventHandler DragLeave
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnDragOver(DragEventArgs e)
|
||
{
|
||
RaiseEvent(e, nameof(DragOver));
|
||
}
|
||
public event EventHandler<DragEventArgs> DragOver
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
protected virtual void OnDrop(DragEventArgs e)
|
||
{
|
||
RaiseEvent(e, nameof(Drop));
|
||
}
|
||
public event EventHandler<DragEventArgs> Drop
|
||
{
|
||
add { AddHandler(value); }
|
||
remove { RemoveHandler(value); }
|
||
}
|
||
|
||
public override string ToString()
|
||
{
|
||
if (!string.IsNullOrEmpty(Name))
|
||
{
|
||
return "#" + Name;
|
||
}
|
||
return base.ToString();
|
||
}
|
||
/// <summary>
|
||
/// 克隆依赖属性,绑定,子元素,触发器
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override object Clone()
|
||
{
|
||
var e = base.Clone() as UIElement;
|
||
if (children != null && children.Count > 0)
|
||
{
|
||
foreach (UIElement item in children)
|
||
{
|
||
e.Children.Add(item.Clone() as UIElement);
|
||
}
|
||
}
|
||
if (triggers != null && triggers.Count > 0)
|
||
{
|
||
foreach (Trigger item in triggers)
|
||
{
|
||
e.Triggers.Add(item);
|
||
}
|
||
}
|
||
if (inheritsValues != null)
|
||
{
|
||
foreach (var item in inheritsValues)
|
||
{
|
||
if (HasLocalOrStyleValue(item.Key, out _))
|
||
{
|
||
e.inheritsValues.Add(item.Key, item.Value);
|
||
}
|
||
}
|
||
}
|
||
return e;
|
||
}
|
||
/// <summary>
|
||
/// 将依赖属性本地值,绑定,子元素,触发器,拷贝到另外个对象
|
||
/// </summary>
|
||
/// <param name="element"></param>
|
||
public void CopyTo(UIElement element)
|
||
{
|
||
base.CopyTo(element);
|
||
if (children != null && children.Count > 0)
|
||
{
|
||
element.Children.Clear();
|
||
foreach (UIElement item in children)
|
||
{
|
||
element.Children.Add(item.Clone() as UIElement);
|
||
}
|
||
}
|
||
if (triggers != null && triggers.Count > 0)
|
||
{
|
||
element.Triggers.Clear();
|
||
foreach (Trigger item in triggers)
|
||
{
|
||
element.Triggers.Add(item);
|
||
}
|
||
}
|
||
}
|
||
|
||
//public IEnumerator<UIElement> GetEnumerator()
|
||
//{
|
||
// return Children.GetEnumerator();
|
||
//}
|
||
|
||
//IEnumerator IEnumerable.GetEnumerator()
|
||
//{
|
||
// return Children.GetEnumerator();
|
||
//}
|
||
//public static UIElement Parse(string str)
|
||
//{
|
||
// return null;
|
||
//}
|
||
|
||
///// <summary>
|
||
///// 字符串解析为UI元素
|
||
///// </summary>
|
||
///// <param name="n"></param>
|
||
//public static implicit operator UIElement(string n)
|
||
//{
|
||
// return Parse(n);
|
||
//}
|
||
|
||
IntPtr id;
|
||
/// <summary>
|
||
/// 获取对象唯一地址
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public IntPtr GetIntPtr()
|
||
{
|
||
if (id == IntPtr.Zero)
|
||
{
|
||
GCHandle h = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
|
||
id = GCHandle.ToIntPtr(h);
|
||
}
|
||
return id;
|
||
}
|
||
[NotCpfProperty]
|
||
internal bool needDispose
|
||
{
|
||
get { return GetFlag(CoreFlags.needDispose); }
|
||
set { SetFlag(CoreFlags.needDispose, value); }
|
||
}
|
||
|
||
internal bool GetFlag(CoreFlags field)
|
||
{
|
||
return (_flags & field) != 0;
|
||
}
|
||
|
||
internal void SetFlag(CoreFlags field, bool value)
|
||
{
|
||
if (value)
|
||
{
|
||
_flags |= field;
|
||
}
|
||
else
|
||
{
|
||
_flags &= (~field);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 用来省内存,8个bool字段只要1字节,省7个字节
|
||
/// </summary>
|
||
private CoreFlags _flags;
|
||
}
|
||
|
||
[Flags]
|
||
enum CoreFlags : byte
|
||
{
|
||
None = 0,
|
||
needDispose = 0b10000000,
|
||
loadStyle = 0b01000000,
|
||
viewRenderRect = 0b00100000,
|
||
transform = 0b00010000,
|
||
inheritsSet = 0b00001000,
|
||
IsArrangeValid = 0b00000100,
|
||
isMeasureValid = 0b00000010,
|
||
isRoot = 0b00000001,
|
||
}
|
||
|
||
struct InheritsValue
|
||
{
|
||
public object Value;
|
||
public ValueFrom ValueForm;
|
||
}
|
||
|
||
enum ValueFrom : byte
|
||
{
|
||
Property,
|
||
Trigger,
|
||
Style,
|
||
Animation,
|
||
}
|
||
}
|