CPF/CPF/UIElement.cs

4256 lines
150 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
}
}