CPF/CPF/Controls/View.cs
2024-01-18 22:09:17 +08:00

2545 lines
107 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 System.Linq;
using CPF.Input;
using CPF.Drawing;
using CPF.Platform;
using CPF.Styling;
using CPF.Animation;
using CPF.Reflection;
using CPF.Design;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Concurrent;
namespace CPF.Controls
{
/// <summary>
/// 基础视图
/// </summary>
[Description("基础视图"), Browsable(false)]
public abstract class View : Control, ITopLevel
{
static ConcurrentDictionary<View, View> views = new ConcurrentDictionary<View, View>();
/// <summary>
/// 当前有效的所有视图
/// </summary>
public static IEnumerable<View> Views { get => views.Values; }
IViewImpl viewImpl;
List<(RadioButtonGroupAttribute group, PropertyInfo property)> radioButtonGroup;
HybridDictionary<string, RadioButtonGroupAttribute> radioButtonGroupProperty;
/// <summary>
/// 这种方式不会调用CreateView();
/// </summary>
/// <param name="view"></param>
public View(IViewImpl view)
{
views.TryAdd(this, this);
IsRoot = true;
Root = this;
viewImpl = view;
viewImpl.PositionChanged = PositionChanged;
viewImpl.Resized = SizeChanged;
viewImpl.ScalingChanged = ScalingChanged;
viewImpl.Activated = Activated;
viewImpl.Deactivated = Deactivated;
viewImpl.SetRoot(this);
var ps = Type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var item in ps)
{
var a = item.GetCustomAttributes(typeof(RadioButtonGroupAttribute), true);
if (a != null && a.Length > 0 && a[0] is RadioButtonGroupAttribute radio)
{
if (radioButtonGroup == null)
{
radioButtonGroup = new List<(RadioButtonGroupAttribute group, PropertyInfo property)>();
radioButtonGroupProperty = new HybridDictionary<string, RadioButtonGroupAttribute>();
}
radioButtonGroupProperty.Add(item.Name, radio);
radioButtonGroup.Add((radio, item));
}
}
}
public View()
{
views.TryAdd(this, this);
IsRoot = true;
Root = this;
viewImpl = CreateView();
viewImpl.PositionChanged = PositionChanged;
viewImpl.Resized = SizeChanged;
viewImpl.ScalingChanged = ScalingChanged;
viewImpl.Activated = Activated;
viewImpl.Deactivated = Deactivated;
viewImpl.SetRoot(this);
var ps = Type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var item in ps)
{
var a = item.GetCustomAttributes(typeof(RadioButtonGroupAttribute), true);
if (a != null && a.Length > 0 && a[0] is RadioButtonGroupAttribute radio)
{
if (radioButtonGroup == null)
{
radioButtonGroup = new List<(RadioButtonGroupAttribute group, PropertyInfo property)>();
radioButtonGroupProperty = new HybridDictionary<string, RadioButtonGroupAttribute>();
}
radioButtonGroupProperty.Add(item.Name, radio);
radioButtonGroup.Add((radio, item));
}
}
styles.CollectionChanged += Styles_CollectionChanged;
}
protected abstract IViewImpl CreateView();
//{
// return Application.GetRuntimePlatform().CreateView();
//}
//internal HybridDictionary<string, UIElement> nameDic = new HybridDictionary<string, UIElement>();
//public View(IViewImpl viewImpl)
//{
// IsRoot = true;
// Root = this;
// this.viewImpl = viewImpl;
// viewImpl.PositionChanged = PositionChanged;
// viewImpl.Resized = SizeChanged;
// viewImpl.Deactivated = Deactivated;
// viewImpl.SetRoot(this);
//}
public IViewImpl ViewImpl { get { return viewImpl; } }
NamedPipe namedPipe;
internal void ConnnetDev(string id)
{
if (namedPipe != null)
{
namedPipe.Dispose();
namedPipe = null;
}
namedPipe = new NamedPipe(id, false);
namedPipe.AcceptMessage += NamedPipe_AcceptMessage;
try
{
namedPipe.WaitForConnection(2000, true);
}
catch (Exception E)
{
MessageBox.Show("连接开发者工具失败:" + E.Message);
}
}
private void NamedPipe_AcceptMessage(NamedPipe pipe, string data, bool conn)
{
if (!conn)
{
pipe.Dispose();
if (pipe == namedPipe)
{
renderRectElement = null;
Invoke(Invalidate);
namedPipe = null;
}
return;
}
if (string.IsNullOrEmpty(data))
{
return;
}
var root = Root;
var cm = CommandMessage<object>.DeserializeWithString(data);
if (cm == null)
{
return;
}
Invoke(() =>
{
if (cm.MessageType == MessageType.GetChildren)
{
IList<ElementTreeNode> list;
list = GetNodeList(cm.Data == null ? 0 : CommandMessage<long>.DeserializeWithString(data).Data);
SendData(new CommandMessage<IList<ElementTreeNode>> { MessageType = MessageType.Children, Data = list });
}
else if (cm.MessageType == MessageType.GetProperties)
{
var list = new List<CPFPropertyInfo>();
var ele = CommandMessage<UIElement>.GetObject(CommandMessage<long>.DeserializeWithString(data).Data);
if (ele != null)
{
var ps = ele.Type.GetProperties();
foreach (var item in ps)
{
try
{
#if NET40
if (item.CanRead && item.GetGetMethod().GetParameters().Length == 0)
{
var v = item.GetValue(ele, null);
#else
if (item.CanRead && item.GetMethod.GetParameters().Length == 0)
{
var v = item.GetValue(ele);
#endif
list.Add(new CPFPropertyInfo { Name = item.Name, Value = v == null ? "" : v.ToString(), IsReadOnly = !item.CanWrite, TypeName = item.PropertyType.FullName, GCHandle = ele.GetIntPtr().ToInt64() });
}
else if (!item.CanRead)
{
list.Add(new CPFPropertyInfo { Name = item.Name, Value = "无法读取", IsReadOnly = true, TypeName = item.PropertyType.FullName, GCHandle = ele.GetIntPtr().ToInt64() });
}
}
catch (Exception e)
{
list.Add(new CPFPropertyInfo { Name = item.Name, Value = e.ToString(), IsReadOnly = true, TypeName = item.PropertyType.FullName, GCHandle = ele.GetIntPtr().ToInt64() });
}
}
if (ele.attachedValues != null)
{
foreach (var item in ele.attachedValues)
{
list.Add(new CPFPropertyInfo { Name = item.Key, Value = item.Value == null ? "" : item.Value.ToString(), IsReadOnly = true, TypeName = item.Value != null ? item.Value.GetType().FullName : "", GCHandle = ele.GetIntPtr().ToInt64() });
}
}
SendData(new CommandMessage<List<CPFPropertyInfo>> { MessageType = MessageType.Properties, Data = list });
}
SetDrawRenderRectangle(ele);
}
else if (cm.MessageType == MessageType.FindElement)
{
//var p = CommandMessage<Point>.DeserializeWithString(data).Data;
//var bounds = Bounds;
var mp = MouseDevice.Location;
Point p = new Point(mp.X, mp.Y);
var po = Position;
p = new Point(p.X - po.X, p.Y - po.Y);
var list = root.HitTest(p / LayoutScaling);
var e = list.FirstOrDefault();
SetDrawRenderRectangle(e);
if (e != null)
{
var parent = e.Parent;
List<UIElement> ps = new List<UIElement>();
while (parent != null)
{
ps.Add(parent);
parent = parent.Parent;
}
Collection<ElementTreeNode> nodes = new Collection<ElementTreeNode>();
var treeRoot = nodes;
var node = CreateNode(root);
nodes.Add(node);
nodes = node.Nodes;
nodes.AddRange(root.GetChildren().Select(CreateNode));
for (int i = ps.Count - 2; i >= 0; i--)
{
var n = ps[i];
nodes = nodes.First(a => a.GCHandle == n.GetIntPtr().ToInt64()).Nodes;
nodes.AddRange(n.GetChildren().Select(CreateNode));
}
SendData(new CommandMessage<IList<ElementTreeNode>> { MessageType = MessageType.ElementTree, Data = treeRoot });
SendData(new CommandMessage<long> { MessageType = MessageType.ShowSelectNode, Data = e.GetIntPtr().ToInt64() });
}
}
else if (cm.MessageType == MessageType.ClearEvent)
{
var p = CommandMessage<Collection<ElementTreeNode>>.DeserializeWithString(data).Data;
ClearEvent(p);
}
else if (cm.MessageType == MessageType.SetValue)
{
var p = CommandMessage<SetPropertyValue>.DeserializeWithString(data).Data;
var ui = CommandMessage<UIElement>.GetObject(p.GCHandle);
if (ui != null)
{
try
{
var type = Type.GetType(p.TypeName);
if (type == null)
{
type = typeof(TextBox).Assembly.GetType(p.TypeName);
}
var v = p.Value.ConvertTo(type);
var pinfo = ui.Type.GetProperty(p.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (pinfo != null && pinfo.GetSetMethod() != null)
{
pinfo.SetValue(ui, v, null);
}
else if (ui.HasProperty(p.Name))
{
ui.SetValue(v, p.Name);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message + (e.InnerException == null ? "" : (":" + e.InnerException)));
}
}
}
else if (cm.MessageType == MessageType.GetPropertyInfo)
{
var p = CommandMessage<GetPropertyInfo>.DeserializeWithString(data).Data;
var ui = CommandMessage<UIElement>.GetObject(p.GCHandle);
if (ui != null)
{
try
{
var type = ui.Type;
string info = p.PropertyName;
var prop = type.GetProperty(p.PropertyName);
if (prop != null)
{
info += "\n" + prop.PropertyType.FullName;
var pm = ui.GetPropertyMetadata(p.PropertyName);
if (pm != null)
{
info += "\n" + "依赖属性";
var pv = ui.GetEffectiveValue(pm);
if (pv != null)
{
if (pv.AnimationValue != null && pv.AnimationValue.Count > 0)
{
//var value = pv.AnimationValue[pv.AnimationValue.Count - 1];
info += "\n" + "来自动画";
}
else if (pv.TriggerValue != null && pv.TriggerValue.Count > 0)
{
var value = pv.TriggerValue[pv.TriggerValue.Count - 1];
info += "\n" + "来自触发器";
if (value.Trigger != null && value.Trigger.Style != null)
{
info += "\n" + "来自样式";
info += "\n" + "行号:" + value.Trigger.Style.Line;
if (!string.IsNullOrWhiteSpace(value.Trigger.Style.Url))
{
info += "\n" + "Url" + value.Trigger.Style.Url;
}
}
}
else if (pv.styleValues != null && pv.styleValues.Count > 0)
{
var value = pv.styleValues[pv.styleValues.Count - 1];
info += "\n" + "来自样式";
if (value.StyleValue != null && value.StyleValue != null)
{
info += "\n" + "行号:" + value.StyleValue.Style.Line;
if (!string.IsNullOrWhiteSpace(value.StyleValue.Style.Url))
{
info += "\n" + "Url" + value.StyleValue.Style.Url;
}
}
}
else if (pv.LocalValue.HasValue)
{
info += "\n" + "来自属性赋值";
}
}
else
{
info += "\n" + "来自默认值或者继承父元素值";
}
}
else
{
info += "\n" + "普通属性";
}
}
else if (p.PropertyName.Contains("."))
{
info += "\n附加属性";
}
SendData(new CommandMessage<string> { MessageType = MessageType.GetPropertyInfo, Data = info });
}
catch (Exception e)
{
MessageBox.Show(e.Message + (e.InnerException == null ? "" : (":" + e.InnerException)));
}
}
}
});
}
void SendData<T>(T data)
{
var by = CommandMessage<T>.SerializeToString(data);
if (namedPipe != null)
{
namedPipe.WriteString(by);
}
}
void GetNodeTree(ElementTreeNode node, UIElement element)
{
node.Name = element.Type.ToString();
var name = element.Name;
if (!string.IsNullOrEmpty(name))
{
node.Name = node.Name + "[" + name + "]";
}
node.Visibility = element.Visibility;
node.GCHandle = element.GetIntPtr().ToInt64();
node.Nodes = new Collection<ElementTreeNode>();
foreach (var item in element.GetChildren())
{
var n = new ElementTreeNode();
GetNodeTree(n, item);
node.Nodes.Add(n);
}
}
ElementTreeNode CreateNode(UIElement element)
{
return new ElementTreeNode
{
GCHandle = element.GetIntPtr().ToInt64(),
Name = GetName(element),
Visibility = element.Visibility,
Nodes = new Collection<ElementTreeNode>()
};
}
IList<ElementTreeNode> GetNodeList(long GCHandle)
{
if (GCHandle != 0)
{
UIElement el = CommandMessage<UIElement>.GetObject(GCHandle);
if (el != null)
{
el.UIElementAdded -= El_UIElementAdded;
el.UIElementAdded += El_UIElementAdded;
el.UIElementRemoved -= El_UIElementRemoved;
el.UIElementRemoved += El_UIElementRemoved;
return el.GetChildren().Select(CreateNode).ToList();
}
else
{
return new ElementTreeNode[0];
}
}
else
{
return new List<ElementTreeNode>() { CreateNode(Root) };
}
}
//IntPtr target;
private void El_UIElementAdded(object sender, UIElementAddedEventArgs e)
{
SendData(new CommandMessage<ValueTuple<long, ElementTreeNode>>
{
MessageType = MessageType.AddChild,
Data = ((sender as UIElement).GetIntPtr().ToInt64(),
new ElementTreeNode
{
GCHandle = e.Element.GetIntPtr().ToInt64(),
Name = GetName(e.Element),
Visibility = e.Element.Visibility,
Nodes = new Collection<ElementTreeNode>()
})
});
}
private void El_UIElementRemoved(object sender, UIElementRemovedEventArgs e)
{
SendData(new CommandMessage<ValueTuple<long, ElementTreeNode>>
{
MessageType = MessageType.RemoveChild,
Data = ((sender as UIElement).GetIntPtr().ToInt64(),
new ElementTreeNode
{
GCHandle = e.Element.GetIntPtr().ToInt64(),
Name = GetName(e.Element),
Visibility = e.Element.Visibility,
Nodes = new Collection<ElementTreeNode>()
})
});
}
void ClearEvent(Collection<ElementTreeNode> nodes)
{
foreach (var item in nodes)
{
UIElement el = CommandMessage<UIElement>.GetObject(item.GCHandle);
el.UIElementAdded -= El_UIElementAdded;
el.UIElementRemoved -= El_UIElementRemoved;
ClearEvent(item.Nodes);
}
}
string GetName(UIElement element)
{
var Name = element.Type.ToString();
var name = element.Name;
if (!string.IsNullOrEmpty(name))
{
Name = Name + "[" + name + "]";
}
return Name;
}
UIElement renderRectElement;
internal void SetDrawRenderRectangle(UIElement element)
{
if (element != null && element.Root == Root)
{
renderRectElement = element;
}
else
{
renderRectElement = null;
}
Root.Invalidate();
}
#region InputManage
InputManager current;
public InputManager InputManager
{
get
{
if (current == null)
{
current = new InputManager(this);
}
return current;
}
}
#endregion
/// <summary>
/// 渲染缩放比例
/// </summary>
public virtual float RenderScaling { get { return viewImpl.RenderScaling; } }
/// <summary>
/// 布局坐标缩放,用于窗体在屏幕和鼠标位置的定位
/// </summary>
public virtual float LayoutScaling { get { return viewImpl.LayoutScaling; } }
public bool CanActivate { get { return viewImpl.CanActivate; } set { viewImpl.CanActivate = value; } }
internal bool offset;
protected virtual void PositionChanged(PixelPoint pos)
{
//System.Diagnostics.Debug.WriteLine(pos);
var scr = Screen;
var p = new Point(pos.X - scr.WorkingArea.X, pos.Y - scr.WorkingArea.Y);
this.VisualOffset = p / ViewImpl.LayoutScaling;
offset = true;
MarginLeft = VisualOffset.X;
MarginTop = VisualOffset.Y;
MarginBottom = "auto";
MarginRight = "auto";
Position = pos;
offset = false;
}
[PropertyChanged(nameof(Position))]
void OnPositionChanged(object newValue, object oldValue, PropertyMetadataAttribute attribute)
{
if (!offset)
{
viewImpl.Position = (PixelPoint)newValue;
}
}
/// <summary>
/// 视图位置,像素坐标
/// </summary>
public PixelPoint Position { get { return GetValue<PixelPoint>(); } set { SetValue(value); } }
void SizeChanged(Size size)
{
//System.Diagnostics.Debug.WriteLine(size + ":" + ActualSize);
if (ActualSize != size)
{
Width = size.Width;
Height = size.Height;
}
}
void ScalingChanged()
{
InvalidateMeasure();
Invalidate();
}
void Activated()
{
//if (this is Popup)
//{
// Debug.WriteLine("Activated");
//}
if (!IsKeyboardFocusWithin)
{
Focus();
}
}
void Deactivated()
{
//if (this is Popup)
//{
// Debug.WriteLine("Deactivated");
//}
var fe = InputManager.KeyboardDevice.FocusedElement;
if (fe != null)
{
fe.InnerLostFocus();
var p = fe.Parent;
while (p != null)
{
p.InnerLostFocus();
p = p.Parent;
}
InputManager.KeyboardDevice.SetFocus(null);
}
InputManager.MouseDevice.Capture(null);
//else
//{
// this.InnerLostFocus();
//}
}
protected override void OnGotFocus(GotFocusEventArgs e)
{
InputManager.MouseDevice.Capture(null);
if (viewImpl.CanActivate)
{
viewImpl.Activate();
}
base.OnGotFocus(e);
}
//public DpiScale GetDpi()
//{
// return viewImpl.GetDpi();
//}
public override Point PointToScreen(Point point)
{
return viewImpl.PointToScreen(point);
}
public void Invalidate(in Rect rect)
{
viewImpl.Invalidate(rect);
}
Cursor cursor;
public void SetCursor(Cursor cursor)
{
if (cursor != this.cursor)
{
this.cursor = cursor;
viewImpl.SetCursor(cursor);
}
}
internal void Capture()
{
viewImpl.Capture();
}
LayoutManager layoutManager;
public LayoutManager LayoutManager
{
get
{
if (layoutManager == null)
{
layoutManager = new LayoutManager(this);
}
return layoutManager;
}
}
internal void ReleaseCapture()
{
viewImpl.ReleaseCapture();
}
public void InvalidateMeasure(UIElement control)
{
//if (IsDisposed || IsDisposing)
//{
// return;
//}
LayoutManager.InvalidateMeasure(control);
}
public void InvalidateArrange(UIElement control)
{
//if (IsDisposed || IsDisposing)
//{
// return;
//}
LayoutManager.InvalidateArrange(control);
}
// public bool EnabledIME { get { return viewImpl.EnabledIME; } set { viewImpl.EnabledIME = value; } }
public void SetIMEEnable(bool value)
{
viewImpl.SetIMEEnable(value);
}
//public void SetIMEPosition(Point point)
//{
// viewImpl.SetIMEPosition(point);
//}
/// <summary>
/// 渲染整个视图
/// </summary>
/// <param name="dc"></param>
/// <param name="rect">剪辑区域</param>
public void RenderView(DrawingContext dc, Rect rect)
{
//LayoutManager.ExecuteLayoutPass();
var scaling = this.RenderScaling;
Matrix old = dc.Transform;
Matrix m = old;
m.ScalePrepend(scaling, scaling);
dc.Transform = m;
viewRect = new Rect(new Point(), ActualSize);
var rc = new Rect(rect.Location / scaling, rect.Size / scaling);
dc.PushClip(rc);
dc.Clear(Color.Transparent);
RenderUIElement(dc, LayoutManager.VisibleUIElements, rc);
dc.PopClip();
dc.Transform = old;
if (renderRectElement != null)
{
dc.PushClip(rect);
var rect1 = renderRectElement.GetContentBounds();
var points = new List<Point>();
points.Add(new Point());
points.Add(new Point((float)Math.Round(rect1.Width * scaling) / scaling, 0));
points.Add(new Point((float)Math.Round(rect1.Width * scaling) / scaling, (float)Math.Round(rect1.Height * scaling) / scaling));
points.Add(new Point(0, (float)Math.Round(rect1.Height * scaling) / scaling));
for (int i = 0; i < points.Count; i++)
{
points[i] = renderRectElement.TransformPoint(points[i]);
}
var p = renderRectElement.Parent;
while (p != null && !p.IsRoot)
{
for (int i = 0; i < points.Count; i++)
{
points[i] = p.TransformPoint(points[i]);
}
p = p.Parent;
}
using (var brush = new SolidColorBrush(Color.FromRgb(255, 0, 0)))
{
var stroke = new Stroke(1);
for (int i = 0; i < points.Count; i++)
{
dc.DrawLine(stroke, brush, points[i] * scaling, points[i == 3 ? 0 : (i + 1)] * scaling);
}
}
dc.PopClip();
}
}
Rect viewRect;
public void RenderUIElement(DrawingContext dc, VisibleUIElement element, in Rect r, in bool drawEffect = false, in Point effectOffset = default(Point))
{
var ele = element.Element;
if (ele.Visibility != Visibility.Visible || ele.Root == null)
{
return;
}
if (r.IntersectsWith(ele.RenderBounds))
{
//var old = dc.AntialiasMode;
dc.AntialiasMode = ele.IsAntiAlias ? AntialiasMode.AntiAlias : AntialiasMode.Default;
if (!drawEffect)
{
var effect = ele.Effect;
if (effect != null)
{
var s = ele.RenderBounds;
s.Intersect(viewRect);
var ss = new Size((s.Width + 2) * RenderScaling, (s.Height + 2) * RenderScaling);
var off = new Point((s.X - 1) * RenderScaling, (s.Y - 1) * RenderScaling);
using (var effectBitmap = new Bitmap((int)ss.Width, (int)ss.Height))
{
using (var effectDc = DrawingContext.FromBitmap(effectBitmap))
{
effectDc.Clear(Color.Transparent);
var rb = ele.RenderBounds;
rb = new Rect(new Point(rb.X - s.X - 1, rb.Y - s.Y - 1) * RenderScaling, new Size(rb.Width + 2, rb.Height + 2) * RenderScaling);
effectDc.PushClip(rb);
effectDc.AntialiasMode = dc.AntialiasMode;
var old = dc.Transform;
var eff = old;
eff.Translate(-off.X + effectOffset.X, -off.Y + effectOffset.Y);
effectDc.Transform = eff;
//element.Element.Render(dcc);
RenderUIElement(effectDc, element, r, true, off);
var offset = Matrix.Identity;
offset.Translate(off.X - effectOffset.X, off.Y - effectOffset.Y);
//effectOffset = off;
dc.Transform = offset;
dc.PushClip(new Rect(0, 0, ss.Width, ss.Height));
effect.DoEffect(dc, effectBitmap);
//dc.DrawImage(effectBitmap, rb, rb);
dc.PopClip();
dc.Transform = old;
effectDc.PopClip();
}
}
return;
}
}
ele.Render(dc);
}
//foreach (var item in element.Children)
var length = element.Children.Count;
for (int i = 0; i < length; i++)
{
var item = element.Children[i];
Rect rect = item.Element.GetContentBounds();
Matrix old = dc.Transform;
Matrix m = old;
var op = item.Element.RenderTransformOrigin;
m.TranslatePrepend(rect.X + op.X.GetActualValue(rect.Width), rect.Y + op.Y.GetActualValue(rect.Height));
m.Prepend(item.Element.RenderTransform.Value);
m.TranslatePrepend(-op.X.GetActualValue(rect.Width), -op.Y.GetActualValue(rect.Height));
dc.Transform = m;
if (item.Element.ClipToBounds)
{
dc.PushClip(new Rect(0, 0, rect.Width, rect.Height));
//item.Element.Render(dc);
RenderUIElement(dc, item, r, false, effectOffset);
dc.PopClip();
}
else
{
RenderUIElement(dc, item, r, false, effectOffset);
}
dc.Transform = old;
}
}
public override bool HitTestCore(Point point)
{
if (VisualClip == null)
{
return new Rect(ActualOffset, ActualSize).Contains(point);
}
else
{
Point offset = VisualOffset;
point.Offset(-offset.X, -offset.Y);
return VisualClip.Contains(point);
}
}
protected override void OnOverrideMetadata(OverrideMetadata overridePropertys)
{
base.OnOverrideMetadata(overridePropertys);
overridePropertys.Override(nameof(Visibility), new UIPropertyMetadataAttribute(Visibility.Collapsed, UIPropertyOptions.AffectsArrange));
overridePropertys.Override(nameof(MarginBottom), new PropertyMetadataAttribute(typeof(FloatField), "Auto"));
overridePropertys.Override(nameof(MarginLeft), new PropertyMetadataAttribute(typeof(FloatField), "Auto"));
overridePropertys.Override(nameof(MarginRight), new PropertyMetadataAttribute(typeof(FloatField), "Auto"));
overridePropertys.Override(nameof(MarginTop), new PropertyMetadataAttribute(typeof(FloatField), "Auto"));
//overridePropertys.Override(nameof(Width), new UIPropertyMetadataAttribute(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure | UIPropertyOptions.AffectsRender));
//overridePropertys.Override(nameof(Height), new UIPropertyMetadataAttribute(typeof(FloatField), "Auto", UIPropertyOptions.AffectsMeasure | UIPropertyOptions.AffectsRender));
}
//[PropertyChanged(nameof(Visibility))]
//void RegisterVisibility(object newValue, object oldValue, PropertyMetadataAttribute attribute)
//{
// viewImpl.SetVisible((Visibility)newValue == Visibility.Visible);
//}
[PropertyChanged(nameof(MarginBottom))]
[PropertyChanged(nameof(MarginLeft))]
[PropertyChanged(nameof(MarginRight))]
[PropertyChanged(nameof(MarginTop))]
void RegisterMargin(object newValue, object oldValue, PropertyMetadataAttribute attribute)
{
if (!offset)
{
if ((!MarginTop.IsAuto && !MarginBottom.IsAuto) || (!MarginLeft.IsAuto && !MarginRight.IsAuto))
{
InvalidateMeasure();
}
else
{
InvalidateArrange();
}
}
}
protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue, PropertyMetadataAttribute propertyMetadata)
{
base.OnPropertyChanged(propertyName, oldValue, newValue, propertyMetadata);
if (propertyName == nameof(Visibility))
{
InputManager.TouchDevice.ClearPoints();
viewImpl.SetVisible((Visibility)newValue == Visibility.Visible);
}
if (!onChecked && radioButtonGroupProperty != null && radiobuttons != null && radioButtonGroupProperty.TryGetValue(propertyName, out var group))
{
if (newValue == null)
{
foreach (var item in radiobuttons)
{
if (item.GroupName == group.GroupName)
{
item.IsChecked = false;
}
}
}
else
{
foreach (var item in radiobuttons)
{
if (item.GroupName == group.GroupName)
{
item.IsChecked = (group.ValueFromDataContext && item.DataContext.Equal(newValue)) || (!group.ValueFromDataContext && item.Content.Equal(newValue));
}
}
}
}
//else if (propertyName == nameof(MarginBottom) || propertyName == nameof(MarginLeft) || propertyName == nameof(MarginRight) || propertyName == nameof(MarginTop))
//{
// if (!offset)
// {
// if ((!MarginTop.IsAuto && !MarginBottom.IsAuto) || (!MarginLeft.IsAuto && !MarginRight.IsAuto))
// {
// InvalidateMeasure();
// }
// else
// {
// InvalidateArrange();
// }
// }
//}
}
List<RadioButton> radiobuttons;
/// <summary>
/// 当前视图内RadioButton的值
/// </summary>
/// <param name="GroupName"></param>
/// <returns></returns>
public object GetRadioButtonValue(string GroupName)
{
if (radiobuttons != null)
{
return radiobuttons.Where(a => a.GroupName == GroupName && a.IsChecked == true).Select(a => a.Content).FirstOrDefault();
}
return null;
}
bool onChecked = false;
internal void CheckedRadioButton(RadioButton radioButton)
{
onChecked = true;
if (radiobuttons != null)
{
var gn = radioButton.GroupName;
foreach (var item in radiobuttons.Where(a => a.GroupName == gn && a.IsChecked == true && a != radioButton))
{
item.IsChecked = false;
}
if (radioButtonGroup != null)
{
foreach (var item in radioButtonGroup)
{
if (item.group.GroupName == gn)
{
if (item.group.ValueFromDataContext)
{
item.property.FastSetValue(this, radioButton.DataContext);
}
else
{
item.property.FastSetValue(this, radioButton.Content);
}
}
}
}
}
onChecked = false;
}
internal void RegisterRadioButton(RadioButton radioButton)
{
if (radiobuttons == null)
{
radiobuttons = new List<RadioButton>();
}
if (radioButton.IsChecked == true)
{
if (radioButtonGroup != null)
{
var gn = radioButton.GroupName;
foreach (var item in radioButtonGroup)
{
if (item.group.GroupName == gn)
{
if (item.group.ValueFromDataContext)
{
item.property.FastSetValue(this, radioButton.DataContext);
}
else
{
item.property.FastSetValue(this, radioButton.Content);
}
}
}
}
}
radiobuttons.Add(radioButton);
}
internal void UnRegisterRadioButton(RadioButton radioButton)
{
if (radioButton.IsChecked == true)
{
if (radioButtonGroup != null)
{
var gn = radioButton.GroupName;
foreach (var item in radioButtonGroup)
{
if (item.group.GroupName == gn)
{
//item.property.FastSetValue(this, null);
}
}
}
}
if (radiobuttons != null)
{
radiobuttons.Remove(radioButton);
}
}
StyleSheet styleSheet;
///// <summary>
///// 解析了的css样式这里不能动态切换样式
///// </summary>
//public StyleSheet StyleSheet
//{
// get
// {
// if (styleSheet == null)
// {
// styleSheet = new StyleSheet();
// }
// return styleSheet;
// }
//}
Styles styles = new Styles();
/// <summary>
/// 样式集合
/// </summary>
[NotCpfProperty]
public Styles Styles
{
get { return styles; }
}
/// <summary>
/// 清除原来样式拷贝view样式过来
/// </summary>
/// <param name="view"></param>
public void LoadStyle(View view)
{
isLoadStyle = true;
this.ClearStyleValues();
if (this.triggers != null)
{
foreach (var trigger in this.triggers.Where(a => a.Style != null).ToArray())
{
this.triggers.Remove(trigger);
}
}
foreach (var item in Find<UIElement>())
{
item.ClearStyleValues();
if (item.triggers != null)
{
foreach (var trigger in item.triggers.Where(a => a.Style != null).ToArray())
{
item.triggers.Remove(trigger);
}
}
}
styles.Clear();
styles.AddRange(view.styles);
if (this.animations != null)
{
this.animations.Clear();
}
else if (view.animations != null)
{
this.animations = new HybridDictionary<string, KeyframesRule>();
}
if (view.animations != null)
{
foreach (var item in view.animations)
{
animations.Add(item);
}
}
styles.Update();
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
SetStyle(item);
}
isLoadStyle = false;
}
/// <summary>
/// css样式比如 Button{Background:rgb(0,142,244);} #Test{Background:rgb(0,142,244);}
/// </summary>
/// <param name="css"></param>
/// <param name="append">附加还是替换</param>
/// <param name="url">用于开发者工具记录的文件路径,可以不设置</param>
public void LoadStyle(string css, bool append = false, string url = null)
{
if (!string.IsNullOrEmpty(css))
{
css = css.TrimStart((char)65279);
}
var parser = new Parser();
if (append && styleSheet != null)
{
var s = parser.Parse(css, url);
//foreach (var item in s.KeyframeDirectives)
//{
// animations.Add(item.Identifier, item);
//}
//foreach (var style in s.StyleRules)
//{
// SetStyle(this, style);
//}
//foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
//{
// foreach (var style in s.StyleRules)
// {
// SetStyle(item, style);
// }
//}
if (s.KeyframeDirectives.Count() > 0 && animations == null)
{
animations = new HybridDictionary<string, KeyframesRule>();
}
if (animations != null)
{
foreach (var item in s.KeyframeDirectives)
{
animations.Add(item.Identifier, item);
}
}
ConvertStyle(s);
foreach (var item in s.Errors)
{
styleSheet.Errors.Add(item);
}
foreach (var item in s.Rules)
{
styleSheet.Rules.Add(item);
}
}
else
{
isLoadStyle = true;
var ss = parser.Parse(css, url);
if (styles.Count > 0)
{
this.ClearStyleValues();
if (this.triggers != null)
{
foreach (var trigger in this.triggers.Where(a => a.Style != null).ToArray())
{
this.triggers.Remove(trigger);
}
}
foreach (var item in Find<UIElement>())
{
item.ClearStyleValues();
if (item.triggers != null)
{
foreach (var trigger in item.triggers.Where(a => a.Style != null).ToArray())
{
item.triggers.Remove(trigger);
}
}
}
}
styles.Clear();
styleSheet = ss;
if (styleSheet.KeyframeDirectives.Count() > 0 && animations == null)
{
animations = new HybridDictionary<string, KeyframesRule>();
}
if (animations != null)
{
animations.Clear();
foreach (var item in styleSheet.KeyframeDirectives)
{
animations.Add(item.Identifier, item);
}
}
//Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
//foreach (var style in styleSheet.StyleRules)
//{
// SetStyle(this, style);
//}
//foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
//{
// foreach (var style in styleSheet.StyleRules)
// {
// SetStyle(item, style);
// }
//}
//Debug.WriteLine(stopwatch.ElapsedMilliseconds);
ConvertStyle(styleSheet);
styles.Update();
//Stopwatch stopwatch = new Stopwatch();
//stopwatch.Start();
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
SetStyle(item);
//foreach (var style in Styles)
//{
// SetStyle(item, style);
//}
}
//Debug.WriteLine(stopwatch.ElapsedMilliseconds);
//Debug.WriteLine("个数" + Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized).Count());
}
if (styleSheet != null)
{
foreach (var item in styleSheet.FontFaceDirectives)
{
if (item.Src.StartsWith("url("))
{
Application.LoadFont(item.Src.Substring(4, item.Src.Length - 5), item.FontFamily.Trim('\'', '"'));
}
else
{
Application.LoadFont(item.Src, item.FontFamily.Trim('\'', '"'));
}
}
}
isLoadStyle = false;
}
private void ConvertStyle(StyleSheet styleSheet)
{
foreach (var item in styleSheet.StyleRules)
{
var selector2 = item.Selector;
SelectorRelation selector = null;
selector = CreateSelector(selector2, selector);
if (selector is Selector selector1)
{
Style style = new Style(selector1);
style.Line = item.Line;
style.Url = styleSheet.Url;
//style.StyleRule = item;
foreach (var pv in item.Declarations)
{
if (pv.Term == null)
{
Debug.WriteLine(styleSheet.Url + " 在第" + pv.Line + "行:" + pv.Name + "的值无效");
continue;
}
var lower = pv.Name.ToLower();
switch (lower)
{
case "animation-name":
style.animation_name = pv.Term.GetValue();
break;
case "animation-duration":
{
var c = pv.Term.GetValue().ToLower();
try
{
if (c.EndsWith("ms"))
{
style.AnimationDuration = TimeSpan.FromMilliseconds(double.Parse(c.TrimEnd('s', 'm')));
}
else if (c.EndsWith("s"))
{
style.AnimationDuration = TimeSpan.FromSeconds(double.Parse(c.TrimEnd('s')));
}
else
{
style.AnimationDuration = TimeSpan.FromMilliseconds(double.Parse(c));
}
}
catch (Exception e)
{
throw new Exception("不支持的时间格式:" + c + ",如果是俄语环境,请尝试 System.Globalization.CultureInfo.CurrentCulture = new System.Globalization.CultureInfo(\"en-US\");", e);
}
break;
}
case "animation-iteration-count":
{
var c = pv.Term.GetValue();
if (c == "infinite")
{
style.AnimationIterationCount = 0;
}
else
{
if (uint.TryParse(c, out var animation_iteration_count))
{
style.AnimationIterationCount = animation_iteration_count;
}
else
{
style.AnimationIterationCount = 1;
}
}
break;
}
case "animation-timing-function":
break;
case "animation-fill-mode":
{
var c = pv.Term.GetValue();
if (c == "none")
{
style.AnimationEndBehavior = EndBehavior.Recovery;
}
else if (c == "forwards")
{
style.AnimationEndBehavior = EndBehavior.Reservations;
}
else
{
throw new Exception("不支持animation-fill-mode的" + c);
}
break;
}
default:
style.Setters.Add(pv.Name, pv.Term.GetValue(), pv.Important);
break;
}
}
styles.Add(style);
}
}
}
bool isLoadStyle;
private void Styles_CollectionChanged(object sender, CollectionChangedEventArgs<Style> e)
{
if (isLoadStyle)
{
if (e.Action == CollectionChangedAction.Add || e.Action == CollectionChangedAction.Replace)
{
e.NewItem.Index = e.Index;
}
return;
}
switch (e.Action)
{
case CollectionChangedAction.Add:
e.NewItem.Index = e.Index;
SetStyle(this, e.NewItem);
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
SetStyle(item, e.NewItem);
}
break;
case CollectionChangedAction.Remove:
this.ClearStyleValue(e.OldItem);
if (this.triggers != null)
{
foreach (var trigger in this.triggers.Where(a => a.Style == e.OldItem).ToArray())
{
this.triggers.Remove(trigger);
}
}
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
item.ClearStyleValue(e.OldItem);
if (item.triggers != null)
{
foreach (var trigger in item.triggers.Where(a => a.Style == e.OldItem).ToArray())
{
item.triggers.Remove(trigger);
}
}
}
break;
case CollectionChangedAction.Replace:
e.NewItem.Index = e.Index;
this.ClearStyleValue(e.OldItem);
if (this.triggers != null)
{
foreach (var trigger in this.triggers.Where(a => a.Style == e.OldItem).ToArray())
{
this.triggers.Remove(trigger);
}
}
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
item.ClearStyleValue(e.OldItem);
if (item.triggers != null)
{
foreach (var trigger in item.triggers.Where(a => a.Style == e.OldItem).ToArray())
{
item.triggers.Remove(trigger);
}
}
}
SetStyle(this, e.NewItem);
foreach (var item in Find<UIElement>().Where(a => !(a is Control control) || control.IsInitialized))
{
SetStyle(item, e.NewItem);
}
break;
case CollectionChangedAction.Sort:
break;
default:
break;
}
}
internal void SetStyle(UIElement item)
{
if (styles.typeNameStyles.TryGetValue(item.Type.Name, out var list))
{
foreach (var style in list)
{
SetStyle(item, style);
}
}
if (!string.IsNullOrWhiteSpace(item.Name) && styles.nameStyles.TryGetValue(item.Name, out var list1))
{
foreach (var style in list1)
{
SetStyle(item, style);
}
}
if (item.classes != null && item.classes.Count > 0)
{
foreach (var c in item.classes)
{
if (styles.classStyles.TryGetValue(c, out var list2))
{
foreach (var style in list2)
{
SetStyle(item, style);
}
}
}
}
foreach (var style in styles.other)
{
SetStyle(item, style);
}
}
private void SetStyle(UIElement item, Style style)
{
if (style.Selector is OrSelector or)
{
foreach (var selectItem in or.Selectors)
{
SelectStyle(item, style, selectItem);
}
}
else
{
SelectStyle(item, style, style.Selector);
}
}
private void SelectStyle(UIElement item, Style style, Selector selector)
{
PropertyEqualsSelector propertyEquals = null;
UIElement peElement = null;
if (IsSelect(selector, item, ref propertyEquals, ref peElement))//style.Selector.Select(item)
{
var prev = selector.Prev;
if (prev == null)
{
//System.Diagnostics.Debug.WriteLine(item);
if (propertyEquals != null)
{
AddTrigger(peElement, style, propertyEquals, selector, item);
}
else
{
SetValue(item, style);
}
//continue;
}
else
{
var element = item;
while (prev != null)
{
if (prev is Selector selector1)
{
if (IsSelect(selector1, element, ref propertyEquals, ref peElement))//selector1.Select(element)
{
if (prev.Prev == null)
{
//System.Diagnostics.Debug.WriteLine(element);
if (propertyEquals != null)
{
AddTrigger(peElement, style, propertyEquals, selector, item);
}
else
{
SetValue(item, style);
}
}
}
else
{
break;
}
}
else if (prev is ChildSelector)
{
element = element.Parent;
}
else
{
var p = element.Parent;
var select = prev.Prev as Selector;
while (p != null)
{
if (IsSelect(select, p, ref propertyEquals, ref peElement))//select.Select(p)
{
if (select.Prev == null)
{
//System.Diagnostics.Debug.WriteLine(element);
if (propertyEquals != null)
{
AddTrigger(peElement, style, propertyEquals, selector, item);
}
else
{
SetValue(item, style);
}
}
element = p;
break;
}
p = p.Parent;
}
if (p == null)
{
break;
}
prev = prev.Prev;
}
prev = prev.Prev;
}
}
}
}
bool IsSelect(Selector selector, UIElement element, ref PropertyEqualsSelector propertyEquals, ref UIElement peElement)
{
if (selector is PropertyEqualsSelector property)
{
propertyEquals = property;
peElement = element;
if (property.HasDot)
{
return true;
}
var r = element.GetPropertyMetadata(property.Property);
if (r != null)
{
if (!(property.Prev is Selector selector1 && selector1.Select(element)))
{
return false;
}
if (!property.HasValue && !string.IsNullOrEmpty(property.ValueString))
{
property.HasValue = true;
property.Value = property.ValueString.ConvertTo(r.PropertyType);
}
return true;
}
return false;
}
return selector.Select(element);
}
private static SelectorRelation CreateSelector(BaseSelector selector2, SelectorRelation selector)
{
if (selector2 is SimpleSelector simple)
{
selector = CreateSimpleSelector(simple, selector);
}
else if (selector2 is AggregateSelectorList aggregate1)
{
switch (aggregate1.Delimiter)
{
case "":
foreach (var a in aggregate1)
{
selector = CreateSelector(a, selector);
}
break;
case ",":
List<Selector> selectors = new List<Selector>();
foreach (var a in aggregate1)
{
selectors.Add((Selector)CreateSelector(a, null));
}
selector = new OrSelector(selectors);
break;
default:
break;
}
}
else if (selector2 is ComplexSelector combinatorSelectors)
{
for (int i = 0; i < combinatorSelectors.Length; i++)
{
var s = combinatorSelectors[i];
switch (s.Delimiter)
{
case Combinator.Child:
selector = CreateSelector(s.Selector, selector);
if (i != combinatorSelectors.Length - 1)
{
selector = ((Selector)selector).Child();
}
break;
case Combinator.Descendent:
selector = CreateSelector(s.Selector, selector);
if (i != combinatorSelectors.Length - 1)
{
selector = ((Selector)selector).Descendant();
}
break;
case Combinator.AdjacentSibling:
case Combinator.Sibling:
case Combinator.Namespace:
break;
}
}
}
return selector;
}
private static SelectorRelation CreateSimpleSelector(SimpleSelector simple, SelectorRelation selector)
{
if (simple.value != null)
{
if (selector == null)
{
selector = new PropertyEqualsSelector(simple.text, simple.value) { ValueString = simple.value, HasValue = false };
}
else
{
selector = selector.PropertyEquals(simple.text, simple.value);
var propertyEqualsSelector = selector as PropertyEqualsSelector;
propertyEqualsSelector.HasValue = false;
propertyEqualsSelector.ValueString = simple.value;
}
}
else
{
switch (simple.SimpleSelectorType)
{
case SimpleSelectorType.All:
selector = new AllSelector();
break;
case SimpleSelectorType.Class://.class.class
var temp = simple.text.Split('.');
foreach (var c in temp)
{
if (!string.IsNullOrEmpty(c))
{
if (selector == null)
{
selector = new ClassSelector(c);
}
else
{
selector = selector.Class(c);
}
}
}
break;
case SimpleSelectorType.Id:
if (selector != null)
{
selector = selector.Name(simple.text);
}
else
{
selector = new NameSelector(simple.text);
}
break;
case SimpleSelectorType.Type://type type.class.class type#id
StringBuilder sb = new StringBuilder();
char tc = (char)0;
foreach (var c in simple._code)
{
if (c == '.' || c == '#')
{
if (selector == null)
{
selector = new TypeNameSelector(sb.ToString());
}
else
{
switch (tc)
{
case '.':
selector = selector.Class(sb.ToString());
break;
case '#':
selector = selector.Name(sb.ToString());
break;
default:
selector = selector.OfType(sb.ToString());
break;
}
}
sb.Clear();
tc = c;
}
else
{
sb.Append(c);
}
}
if (sb.Length > 0)
{
if (selector == null)
{
selector = new TypeNameSelector(sb.ToString());
}
else
{
switch (tc)
{
case '.':
selector = selector.Class(sb.ToString());
break;
case '#':
selector = selector.Name(sb.ToString());
break;
default:
selector = selector.OfType(sb.ToString());
break;
}
}
}
break;
case SimpleSelectorType.PseudoElement:
case SimpleSelectorType.PseudoClass:
case SimpleSelectorType.AttributeUnmatched:
case SimpleSelectorType.AttributeMatch:
case SimpleSelectorType.AttributeNegatedMatch:
case SimpleSelectorType.AttributeSpaceSeparated:
case SimpleSelectorType.AttributeStartsWith:
case SimpleSelectorType.AttributeEndsWith:
case SimpleSelectorType.AttributeContains:
case SimpleSelectorType.AttributeDashSeparated:
default:
break;
}
}
return selector;
}
/// <summary>
/// 内部元素初始化内部所有元素都会调用这个可以用来代替CSS实现复杂的属性或者模板设置重写必须保留base.OnElementInitialize。设置Control的Template来替换模板就需要在base.OnElementInitialize之前对于非Control的元素复用的话每次添加到元素树的时候都会触发
/// </summary>
internal protected virtual void OnElementInitialize(UIElement element)
{
if (element is Control control)
{
control.Initialize();
}
else
{
element.LoadStyle();
}
}
///// <summary>
///// 对于初始化过的元素被移除的时候进行终结操作比如在OnElementInitialize绑定的事件可以在这里取消绑定
///// </summary>
///// <param name="element"></param>
//internal protected virtual void OnElementFinalize(UIElement element)
//{
//}
internal List<(Delegate, UIElement)> afterStyles;
protected override void OnInitialized()
{
base.OnInitialized();
if (afterStyles != null)
{
foreach (var item in afterStyles)
{
item.Item1.Method.FastInvoke(item.Item1.Target, item.Item2);
}
afterStyles.Clear();
}
}
/// <summary>
/// 加载样式文件可以是内嵌或者在线或者本地的文件需要是utf8编码
/// </summary>
/// <param name="path"></param>
/// <param name="append"></param>
public void LoadStyleFile(string path, bool append = false)
{
ResourceManager.GetText(path, a =>
{
if (!string.IsNullOrWhiteSpace(a))
{
Invoke(() =>
{
LoadStyle(a, append, path);
});
}
});
}
HybridDictionary<string, KeyframesRule> animations;
//internal void SetStyle(UIElement item, StyleRule style)
//{
// if (style.Selector.Select(item))
// {
// if (style.Selector is AggregateSelectorList selectorList)
// {
// if (selectorList.Delimiter == "")
// {
// if (selectorList[1] is SimpleSelector simpleSelector && simpleSelector.value != null)
// {
// AddTrigger(item, style, simpleSelector);
// }
// else
// {
// SetValue(item, style);
// }
// }
// else if (selectorList.Delimiter == ",")
// {
// var asl = selectorList.FirstOrDefault(a => a is AggregateSelectorList && (a as AggregateSelectorList).Delimiter == "");
// if (asl != null && asl.Select(item))
// {
// var simpleSelector = ((AggregateSelectorList)asl)[1] as SimpleSelector;
// AddTrigger(item, style, simpleSelector);
// }
// else
// {
// var simpleSelector = selectorList.FirstOrDefault(a => a is SimpleSelector) as SimpleSelector;
// if (simpleSelector != null && simpleSelector.value != null && simpleSelector.Select(item))
// {
// AddTrigger(item, style, simpleSelector);
// }
// else
// {
// SetValue(item, style);
// }
// }
// }
// }
// else if (style.Selector is ComplexSelector combinatorSelectors)
// {
// if (combinatorSelectors[0].Selector is SimpleSelector simpleSelector)
// {
// if (combinatorSelectors[1].Selector is AggregateSelectorList selectorList1)
// {
// if (selectorList1.Delimiter == "")
// {
// if (selectorList1[1] is SimpleSelector simpleSelector1 && simpleSelector1.value != null)
// {
// if (combinatorSelectors.Length == 2)
// {
// AddTrigger(item, style, simpleSelector1);
// }
// else
// {
// var parent = item.Parent;
// while (parent != null)
// {
// if (selectorList1.Select(parent))
// {
// break;
// }
// parent = parent.Parent;
// }
// if (parent != null)
// {
// ComplexSelector selectors = new ComplexSelector();
// for (int i = 1; i < combinatorSelectors.Length; i++)
// {
// selectors.AppendSelector(combinatorSelectors[i].Selector, combinatorSelectors[i].Delimiter);
// }
// //selectors.AppendSelector(combinatorSelectors[2].Selector, combinatorSelectors[2].Delimiter);
// AddTrigger(parent, style, simpleSelector1, Relation.Me.Find(a => selectors.Select(a)));
// }
// }
// }
// else
// {
// SetValue(item, style);
// }
// }
// else if (selectorList1.Delimiter == ",")
// {
// var asl = selectorList1.FirstOrDefault(a => a is AggregateSelectorList && (a as AggregateSelectorList).Delimiter == "");
// if (asl != null && asl.Select(item))
// {
// var simpleSelector1 = ((AggregateSelectorList)asl)[1] as SimpleSelector;
// AddTrigger(item, style, simpleSelector1);
// }
// else
// {
// var simpleSelector1 = selectorList1.FirstOrDefault(a => a is SimpleSelector) as SimpleSelector;
// if (simpleSelector1 != null && simpleSelector1.value != null && simpleSelector1.Select(item))
// {
// AddTrigger(item, style, simpleSelector1);
// }
// else
// {
// SetValue(item, style);
// }
// }
// }
// }
// else if (combinatorSelectors[1].Selector is SimpleSelector simpleSelector2)
// {
// if (simpleSelector2.value != null)
// {
// AddTrigger(item, style, simpleSelector2);
// }
// else
// {
// SetValue(item, style);
// }
// }
// }
// else if (combinatorSelectors[0].Selector is AggregateSelectorList selectorList1)
// {//设置给祖先触发器
// if (selectorList1.Delimiter != "")
// {
// throw new Exception("不支持" + style.Selector);
// }
// else
// {
// var parent = item.Parent;
// while (parent != null)
// {
// if (selectorList1.Select(parent))
// {
// break;
// }
// parent = parent.Parent;
// }
// if (parent != null)
// {
// //if (combinatorSelectors.Length > 2)
// //{
// ////ComplexSelector selectors = new ComplexSelector();
// ////for (int i = 1; i < combinatorSelectors.Length; i++)
// ////{
// //// selectors.AppendSelector(combinatorSelectors[i].Selector, combinatorSelectors[i].Delimiter);
// ////}
// if (combinatorSelectors.Count(a => a.Delimiter == Combinator.Child) == combinatorSelectors.Length)
// {
// var relation = Relation.Me;
// for (int i = 1; i < combinatorSelectors.Length; i++)
// {
// var selector = combinatorSelectors[i].Selector;
// relation = relation.Children(a => selector.Select(a));
// }
// AddTrigger(parent, style, selectorList1[1] as SimpleSelector, relation);
// }
// else
// {
// AddTrigger(parent, style, selectorList1[1] as SimpleSelector, Relation.Me.Find(a => combinatorSelectors.Select(a)));
// }
// //}
// //else
// //{
// // var sss = combinatorSelectors[1].Selector;
// // if (combinatorSelectors[0].Delimiter == Combinator.Child)
// // {
// // var ss = combinatorSelectors[1].Selector;
// // AddTrigger(item.Parent, style, selectorList1[1] as SimpleSelector, Relation.Me.Children(a => ss.Select(a)));
// // }
// // else
// // {
// // AddTrigger(parent, style, selectorList1[1] as SimpleSelector, Relation.Me.Find(a => sss.Select(a)));
// // }
// //}
// }
// //switch (combinatorSelectors[0].Delimiter)
// //{
// // case Combinator.Child:
// // var ss = combinatorSelectors[1].Selector;
// // AddTrigger(item.Parent, style, selectorList1[1] as SimpleSelector, Relation.Me.Children(a => ss.Select(a)));
// // break;
// // case Combinator.Descendent:
// // var parent = item.Parent;
// // while (parent != null)
// // {
// // if (selectorList1[0].Select(parent))
// // {
// // break;
// // }
// // parent = parent.Parent;
// // }
// // var sss = combinatorSelectors[1].Selector;
// // AddTrigger(parent, style, selectorList1[1] as SimpleSelector, Relation.Me.Find(a => sss.Select(a)));
// // break;
// // default:
// // throw new Exception("不支持" + style.Selector);
// //}
// }
// }
// else
// {
// throw new Exception("不支持" + combinatorSelectors[0].Selector);
// }
// }
// else if (style.Selector is SimpleSelector simpleSelector && simpleSelector.value != null)
// {
// AddTrigger(item, style, simpleSelector);
// }
// else
// {
// SetValue(item, style);
// }
// }
//}
//static Type keyframe = typeof(KeyFrame<>);
static Type ViewFillType = typeof(ViewFill);
static Type SolidColorFillType = typeof(SolidColorFill);
bool AddTrigger(UIElement pItem, Style style, PropertyEqualsSelector propertyEqualsSelector, Selector selector, UIElement target)
{
Trigger t;
if (pItem.triggers != null && (t = pItem.triggers.FirstOrDefault(a => a.Style == style)) != null)
{
if (!propertyEqualsSelector.HasDot && propertyEqualsSelector.Select(pItem))
{
foreach (var setter in style.Setters)
{
if (target.HasProperty(setter.Key))
{
if (!setter.Value.HasValue)
{
setter.Value.HasValue = true;
setter.Value.Value = setter.Value.CssValue.ConvertTo(target.GetPropertyMetadata(setter.Key).PropertyType);
}
target.SetTriggerValue(setter.Key, t, setter.Value);
}
else
{
try
{
var property = target.Type.GetProperty(setter.Key);
if (property != null)
{
if (!setter.Value.HasValue)
{
setter.Value.HasValue = true;
setter.Value.Value = setter.Value.CssValue.ConvertTo(property.PropertyType);
}
property.FastSetValue(target, setter.Value.Value);
}
}
catch (Exception e)
{
Debug.WriteLine("设置样式时出错:" + style.Selector + " 属性名:" + setter.Key + " " + e.Message);
}
}
}
}
return false;
}
//var p = item.GetPropertyMetadata(propertyEqualsSelector.Property);
//if (p == null)
//{
// Debug.WriteLine(item + "未找到属性:" + propertyEqualsSelector.Property);
//}
object value = propertyEqualsSelector.Value;
Func<object, bool> pc;
if (propertyEqualsSelector.HasDot)
{
pc = a =>
{
if (a != null)
{
if (!propertyEqualsSelector.HasValue && !string.IsNullOrEmpty(propertyEqualsSelector.ValueString))
{
propertyEqualsSelector.HasValue = true;
propertyEqualsSelector.Value = propertyEqualsSelector.ValueString.ConvertTo(a.GetType());
}
return a.Equals(propertyEqualsSelector.Value);
}
return propertyEqualsSelector.ValueString == "null";
};
}
else
{
pc = a => (a != null && a.Equals(value) || (a == null && value == null));
}
t = new Trigger
{
Property = propertyEqualsSelector.Property,
PropertyConditions = pc,
TargetRelation = style.GetRelation(selector),
Style = style,
AnimationDuration = style.AnimationDuration,
AnimationEndBehavior = style.AnimationEndBehavior,
AnimationIterationCount = style.AnimationIterationCount
};
foreach (var setter in style.Setters)
{
t.Setters.Add(setter.Key, setter.Value);
}
string animation_name = style.animation_name;
if (!string.IsNullOrWhiteSpace(animation_name) && animations != null)
{
if (animations.TryGetValue(animation_name, out KeyframesRule kf))
{
var story = new Storyboard();
foreach (KeyframeRule k in kf.Declarations)
{
var timeline = new Timeline(k.Timeline);
foreach (var v in k.Declarations)
{
var pm = pItem.GetPropertyMetadata(v.Name);
if (pm != null)
{
var pt = pm.PropertyType;
//var type = keyframe.MakeGenericType(pt == ViewFillType ? SolidColorFillType : pt);
var type = KeyFrame<int>.KeyFrameTypes[pt == ViewFillType ? SolidColorFillType : pt];
var kk = type();
kk.Property = v.Name;
kk.SetValue("Value", v.Term.GetValue().ConvertTo(pt));
timeline.KeyFrames.Add(kk);
}
}
story.Timelines.Add(timeline);
}
t.Animation = story;
}
}
pItem.Triggers.Add(t);
return true;
}
//private void AddTrigger(UIElement item, StyleRule style, SimpleSelector simpleSelector, Relation relation = null)
//{
// if (item.triggers != null && item.triggers.FirstOrDefault(a => a.Style == style) != null)
// {
// return;
// }
// var p = item.GetPropertyMetadata(simpleSelector.text);
// if (p == null)
// {
// Debug.WriteLine(item + "未找到属性:" + simpleSelector.text);
// }
// object value = null;
// //try
// //{
// value = simpleSelector.value.ConvertTo(p.PropertyType);
// //}
// //catch (Exception)
// //{ }
// Trigger t = null;
// switch (simpleSelector.SimpleSelectorType)
// {
// case SimpleSelectorType.AttributeMatch:
// t = new Trigger
// {
// Property = simpleSelector.text,
// PropertyConditions = a => (a != null && a.Equals(value) || (a == null && value == null)),
// TargetRelation = relation,
// Style = style,
// };
// break;
// case SimpleSelectorType.AttributeNegatedMatch:
// t = new Trigger
// {
// Property = simpleSelector.text,
// PropertyConditions = a => !((a != null && a.Equals(value) || (a == null && value == null))),
// TargetRelation = relation,
// Style = style,
// };
// break;
// default:
// throw new Exception("暂时不支持" + simpleSelector.ToString());
// }
// string animation_name = null;
// TimeSpan animation_duration = TimeSpan.FromSeconds(0.5);
// uint animation_iteration_count = 1;
// foreach (var sdv in style.Declarations)
// {
// var lower = sdv.Name.ToLower();
// //if (item.HasProperty(sdv.Name))
// //{
// t.Setters.Add(sdv.Name, sdv.Term.GetValue());
// //}
// if (lower == "animation-name")
// {
// animation_name = sdv.Term.GetValue();
// }
// else if (lower == "animation-duration")
// {
// var c = sdv.Term.GetValue().ToLower();
// try
// {
// if (c.EndsWith("ms"))
// {
// animation_duration = TimeSpan.FromMilliseconds(double.Parse(c.TrimEnd('s', 'm')));
// }
// else if (c.EndsWith("s"))
// {
// animation_duration = TimeSpan.FromSeconds(double.Parse(c.TrimEnd('s')));
// }
// else
// {
// animation_duration = TimeSpan.FromMilliseconds(double.Parse(c));
// }
// }
// catch (Exception)
// {
// throw new Exception("不支持的时间格式:" + c);
// }
// }
// else if (lower == "animation-iteration-count")
// {
// var c = sdv.Term.GetValue();
// if (c == "infinite")
// {
// animation_iteration_count = 0;
// }
// else
// {
// if (!uint.TryParse(c, out animation_iteration_count))
// {
// animation_iteration_count = 1;
// }
// }
// }
// else if (lower == "animation-timing-function")
// {
// }
// else if (lower == "animation-fill-mode")
// {
// var c = sdv.Term.GetValue();
// if (c == "none")
// {
// t.AnimationEndBehavior = EndBehavior.Recovery;
// }
// else if (c == "forwards")
// {
// t.AnimationEndBehavior = EndBehavior.Reservations;
// }
// else
// {
// throw new Exception("不支持animation-fill-mode的" + c);
// }
// }
// }
// if (!string.IsNullOrWhiteSpace(animation_name))
// {
// if (animations.TryGetValue(animation_name, out KeyframesRule kf))
// {
// var story = new Storyboard();
// foreach (KeyframeRule k in kf.Declarations)
// {
// var timeline = new Timeline(k.Timeline);
// foreach (var v in k.Declarations)
// {
// var pm = item.GetPropertyMetadata(v.Name);
// if (pm != null)
// {
// var pt = pm.PropertyType;
// //if (pt == ViewFillType)
// //{
// // pt = SolidColorFillType;
// //}
// var type = keyframe.MakeGenericType(pt == ViewFillType ? SolidColorFillType : pt);
// var kk = type.GetConstructor(new Type[] { }).FastInvoke() as KeyFrame;
// kk.Property = v.Name;
// //type.GetProperty("Value").FastSetValue(kk, v.Term.GetValue().ConvertTo(pt));
// kk.SetValue("Value", v.Term.GetValue().ConvertTo(pt));
// timeline.KeyFrames.Add(kk);
// }
// }
// story.Timelines.Add(timeline);
// }
// t.Animation = story;
// }
// }
// t.AnimationDuration = animation_duration;
// t.AnimationIterationCount = animation_iteration_count;
// item.Triggers.Add(t);
//}
private static void SetValue(UIElement item, Style style)
{
foreach (var setter in style.Setters)
{
if (item.HasProperty(setter.Key))
{
//if (!setter.Value.HasValue)
//{
// setter.Value.HasValue = true;
// setter.Value.Value = setter.Value.CssValue.ConvertTo(item.GetPropertyMetadata(setter.Key).PropertyType);
//}
setter.Value.ConvertValue(item.GetPropertyMetadata(setter.Key).PropertyType);
item.SetStyleValue(setter.Key, setter.Value);
}
else
{
try
{
var property = item.Type.GetProperty(setter.Key);
if (property != null)
{
//if (!setter.Value.HasValue)
//{
// setter.Value.HasValue = true;
// setter.Value.Value = setter.Value.CssValue.ConvertTo(property.PropertyType);
//}
setter.Value.ConvertValue(property.PropertyType);
property.FastSetValue(item, setter.Value.Value);
}
else
{
var index = setter.Key.IndexOf('-');
if (index > 0)
{
property = item.Type.GetProperty(setter.Key.Substring(0, index));
if (property != null)
{
var temp = setter.Key.Split('-');
var lIndex = 0;
if (temp.Length > 2 && (temp[1] == "*" || int.TryParse(temp[1], out lIndex)))
{
var value = property.FastGetValue(item);
if (value is IEnumerable enumerable)
{
if (temp[1] == "*")
{
foreach (var it in enumerable)
{
if (it != null)
{
property = it.GetType().GetProperty(temp[2]);
if (property != null)
{
setter.Value.ConvertValue(property.PropertyType);
property.FastSetValue(it, setter.Value.Value);
}
}
}
}
else
{
var it = enumerable.OfType<object>().ElementAtOrDefault(lIndex);
if (it != null)
{
property = it.GetType().GetProperty(temp[2]);
if (property != null)
{
//if (!setter.Value.HasValue)
//{
// setter.Value.HasValue = true;
// setter.Value.Value = setter.Value.CssValue.ConvertTo(property.PropertyType);
//}
setter.Value.ConvertValue(property.PropertyType);
property.FastSetValue(it, setter.Value.Value);
}
}
}
}
}
else
{
var value = property.FastGetValue(item);
if (value != null)
{
property = value.GetType().GetProperty(temp[1]);
if (property != null)
{
//if (!setter.Value.HasValue)
//{
// setter.Value.HasValue = true;
// setter.Value.Value = setter.Value.CssValue.ConvertTo(property.PropertyType);
//}
setter.Value.ConvertValue(property.PropertyType);
property.FastSetValue(value, setter.Value.Value);
}
}
}
}
}
}
}
catch (Exception e)
{
Debug.WriteLine("设置样式时出错:" + style.Selector + " 属性名:" + setter.Key + " " + e.Message);
}
}
}
//foreach (var sdv in style.Declarations)
//{
// if (item.HasProperty(sdv.Name))
// {
// try
// {
// item.SetStyleValue(sdv.Name, style, sdv, sdv.Value.HasValue ? sdv.Value.Value : sdv.Term.GetValue());
// }
// catch (Exception e)
// {
// Debug.WriteLine("设置样式时出错:" + sdv + " " + e.Message);
// }
// }
// else
// {
// try
// {
// var property = item.Type.GetProperty(sdv.Name);
// if (property != null)
// {
// var value = sdv.Value.HasValue ? sdv.Value.Value : sdv.Term.GetValue();
// if (value != null && !sdv.Value.HasValue)
// {
// var vType = value.GetType();
// if (vType != property.PropertyType && !property.PropertyType.IsAssignableFrom(vType))
// {
// value = value.ConvertTo(property.PropertyType);
// }
// sdv.Value = new EffectiveValueEntry { HasValue = true, Value = value };
// }
// else
// {
// value = sdv.Value.Value;
// }
// property.FastSetValue(item, value);
// }
// }
// catch (Exception e)
// {
// Debug.WriteLine("设置样式时出错:" + sdv + " " + e.Message);
// }
// }
//}
}
/// <summary>
/// 子元素
/// </summary>
[NotCpfProperty]
public virtual new UIElementCollection Children
{
get
{
return base.Children;
}
}
/// <summary>
/// 视图所在的屏幕
/// </summary>
[NotCpfProperty]
public virtual Screen Screen { get { return viewImpl.Screen; } }
///// <summary>
///// 背景填充
///// </summary>
//[UIPropertyMetadata(null, UIPropertyOptions.AffectsRender)]
//public ViewFill Background
//{
// get { return (ViewFill)GetValue(); }
// set { SetValue(value); }
//}
//protected override void OnRender(DrawingContext dc)
//{
// var back = Background;
// var size = ActualSize;
// if (back != null && size.Width > 0 && size.Height > 0)
// {
// using (var b = back.CreateBrush(new Rect(new Point(), size), dc))
// {
// dc.FillRectangle(b, new Rect(0, 0, size.Width, size.Height));
// }
// }
//}
protected override void Dispose(bool disposing)
{
views.TryRemove(this, out _);
base.Dispose(disposing);
if (viewImpl != null)
{
viewImpl.Dispose();
//viewImpl = null;
}
}
}
/// <summary>
/// 绑定RadioButton分组的值只能在View里使用
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class RadioButtonGroupAttribute : Attribute
{
/// <summary>
/// 绑定RadioButton分组的值只能在View里使用默认是用RadioButton的Content作为绑定值
/// </summary>
/// <param name="groupName"></param>
/// <param name="valueFromDataContext">用RadioButton的DataContext作为绑定的值默认是用RadioButton的Content</param>
public RadioButtonGroupAttribute(string groupName, bool valueFromDataContext = false)
{
this.GroupName = groupName;
this.ValueFromDataContext = valueFromDataContext;
}
public string GroupName { get; }
/// <summary>
/// 用RadioButton的DataContext作为绑定的值默认是用RadioButton的Content
/// </summary>
public bool ValueFromDataContext { get; }
}
}