From 0e2e5e6a6821be290cc48358468d9a08f3fd8c35 Mon Sep 17 00:00:00 2001 From: fengjiayi <12821976+ning_xi@user.noreply.gitee.com> Date: Tue, 27 Jan 2026 17:35:09 +0800 Subject: [PATCH] =?UTF-8?q?chore(temp)=20:=20=E4=B8=8D=E9=87=8D=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=96=87=E4=BB=B6=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Workbench/Temp/Class1.cs | 478 +++++++++++++++++++++++++++ Workbench/Temp/Xaml.cs | 146 +++++++++ Workbench/Temp/XamlScript.cs | 613 +++++++++++++++++++++++++++++++++++ 3 files changed, 1237 insertions(+) create mode 100644 Workbench/Temp/Class1.cs create mode 100644 Workbench/Temp/Xaml.cs create mode 100644 Workbench/Temp/XamlScript.cs diff --git a/Workbench/Temp/Class1.cs b/Workbench/Temp/Class1.cs new file mode 100644 index 0000000..577ef41 --- /dev/null +++ b/Workbench/Temp/Class1.cs @@ -0,0 +1,478 @@ +using Serein.Library; +using Serein.Script; +using System.ComponentModel; +using System.Diagnostics; +using System.Reflection; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Markup; +using System.Windows.Media; + + +namespace CXLims.Software.WPFTemplate +{ + + + [ContentProperty(nameof(XamlScript.ScriptContent))] + public class XamlScript : DependencyObject + { + /// + /// 脚本节点内容 + /// + public string? ScriptContent { get; set; } + + public override string ToString() => ScriptContent ?? string.Empty; + } + + public enum XamlScriptTriggerType + { + /// + /// 初始化时触发 + /// + Loaded, + /// + /// 属性变更触发 + /// + Property, + /// + /// 指定事件触发 + /// + Event, + /// + /// 获得/失去焦点触发 + /// + Focus + } + + /*public enum FindPriorityType + { + /// + /// 不查找 + /// + None, + /// + /// 视觉优先 + /// + Visual, + /// + /// 逻辑优先 + /// + Logical, + /// + /// 仅视觉 + /// + VisualOnly, + /// + /// 仅逻辑 + /// + LogicalOnly, + }*/ + + + + public static class ScriptMethod + { + public static void debug(object value) + { + Debug.WriteLine(value); + } + } + + + public static class XScript + { + static XScript() + { + LoadType(typeof(ScriptBaseFunc)); + LoadType(typeof(ScriptMethod)); + } + + private static void LoadType(Type type) + { + // 获取方法 + var tempMethods = type.GetMethods().Where(method => + method.IsStatic && + !(method.Name.Equals("GetHashCode") + || method.Name.Equals("Equals") + || method.Name.Equals("ToString") + || method.Name.Equals("GetType") + )).Select(method => (method.Name, method)).ToArray(); + // 挂在方法 + foreach ((string name, MethodInfo method) item in tempMethods) + { + SereinScript.AddStaticFunction(item.name, item.method); + } + } + + #region 附加属性定义 + + + public static readonly DependencyProperty XamlScriptProperty = + DependencyProperty.RegisterAttached( + "XamlScript", + typeof(XamlScript), + typeof(XScript), + new PropertyMetadata(null, OnXamlScriptChanged)); + + /// 触发类型 + public static readonly DependencyProperty TriggerTypeProperty = + DependencyProperty.RegisterAttached( + "TriggerType", + typeof(XamlScriptTriggerType), + typeof(XScript), + new PropertyMetadata(XamlScriptTriggerType.Loaded)); + + /// 触发属性名称 + public static readonly DependencyProperty TriggerNameProperty = + DependencyProperty.RegisterAttached( + "TriggerName", + typeof(string), + typeof(XScript), + new PropertyMetadata("")); + + + + /// 脚本返回结果,可用于外部绑定 + public static readonly DependencyProperty ReturnProperty = + DependencyProperty.RegisterAttached( + "Return", + typeof(object), + typeof(XScript), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); + + + + + public static void SetXamlScript(DependencyObject element, XamlScript value) => element.SetValue(XamlScriptProperty, value); + public static XamlScript GetXamlScript(DependencyObject element) => (XamlScript)element.GetValue(XamlScriptProperty); + + public static void SetTriggerType(DependencyObject element, XamlScriptTriggerType value) => element.SetValue(TriggerTypeProperty, value); + public static XamlScriptTriggerType GetTriggerType(DependencyObject element) => (XamlScriptTriggerType)element.GetValue(TriggerTypeProperty); + + public static void SetTriggerName(DependencyObject element, string value) => element.SetValue(TriggerNameProperty, value); + public static string GetTriggerName(DependencyObject element) => (string)element.GetValue(TriggerNameProperty); + + public static void SetReturn(DependencyObject element, object value) => element.SetValue(ReturnProperty, value); + public static object GetReturn(DependencyObject element) => element.GetValue(ReturnProperty); + + + + public static readonly DependencyProperty ParamData1Property = DependencyProperty.RegisterAttached("ParamData1", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData2Property = DependencyProperty.RegisterAttached("ParamData2", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData3Property = DependencyProperty.RegisterAttached("ParamData3", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData4Property = DependencyProperty.RegisterAttached("ParamData4", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData5Property = DependencyProperty.RegisterAttached("ParamData5", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData6Property = DependencyProperty.RegisterAttached("ParamData6", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData7Property = DependencyProperty.RegisterAttached("ParamData7", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static readonly DependencyProperty ParamData8Property = DependencyProperty.RegisterAttached("ParamData8", typeof(object), typeof(XScript), new PropertyMetadata(null)); + public static void SetParamData1(DependencyObject element, object value) => element.SetValue(ParamData1Property, value); public static object GetParamData1(DependencyObject element) => element.GetValue(ParamData1Property); + public static void SetParamData2(DependencyObject element, object value) => element.SetValue(ParamData2Property, value); public static object GetParamData2(DependencyObject element) => element.GetValue(ParamData2Property); + public static void SetParamData3(DependencyObject element, object value) => element.SetValue(ParamData3Property, value); public static object GetParamData3(DependencyObject element) => element.GetValue(ParamData3Property); + public static void SetParamData4(DependencyObject element, object value) => element.SetValue(ParamData4Property, value); public static object GetParamData4(DependencyObject element) => element.GetValue(ParamData4Property); + public static void SetParamData5(DependencyObject element, object value) => element.SetValue(ParamData5Property, value); public static object GetParamData5(DependencyObject element) => element.GetValue(ParamData5Property); + public static void SetParamData6(DependencyObject element, object value) => element.SetValue(ParamData6Property, value); public static object GetParamData6(DependencyObject element) => element.GetValue(ParamData6Property); + public static void SetParamData7(DependencyObject element, object value) => element.SetValue(ParamData7Property, value); public static object GetParamData7(DependencyObject element) => element.GetValue(ParamData7Property); + public static void SetParamData8(DependencyObject element, object value) => element.SetValue(ParamData8Property, value); public static object GetParamData8(DependencyObject element) => element.GetValue(ParamData8Property); + + + public static readonly DependencyProperty ParamName1Property = DependencyProperty.RegisterAttached("ParamName1", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName2Property = DependencyProperty.RegisterAttached("ParamName2", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName3Property = DependencyProperty.RegisterAttached("ParamName3", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName4Property = DependencyProperty.RegisterAttached("ParamName4", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName5Property = DependencyProperty.RegisterAttached("ParamName5", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName6Property = DependencyProperty.RegisterAttached("ParamName6", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName7Property = DependencyProperty.RegisterAttached("ParamName7", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName8Property = DependencyProperty.RegisterAttached("ParamName8", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static void SetParamName1(DependencyObject element, string value) => element.SetValue(ParamName1Property, value); public static string GetParamName1(DependencyObject element) => (string)element.GetValue(ParamName1Property); + public static void SetParamName2(DependencyObject element, string value) => element.SetValue(ParamName2Property, value); public static string GetParamName2(DependencyObject element) => (string)element.GetValue(ParamName2Property); + public static void SetParamName3(DependencyObject element, string value) => element.SetValue(ParamName3Property, value); public static string GetParamName3(DependencyObject element) => (string)element.GetValue(ParamName3Property); + public static void SetParamName4(DependencyObject element, string value) => element.SetValue(ParamName4Property, value); public static string GetParamName4(DependencyObject element) => (string)element.GetValue(ParamName4Property); + public static void SetParamName5(DependencyObject element, string value) => element.SetValue(ParamName5Property, value); public static string GetParamName5(DependencyObject element) => (string)element.GetValue(ParamName5Property); + public static void SetParamName6(DependencyObject element, string value) => element.SetValue(ParamName6Property, value); public static string GetParamName6(DependencyObject element) => (string)element.GetValue(ParamName6Property); + public static void SetParamName7(DependencyObject element, string value) => element.SetValue(ParamName7Property, value); public static string GetParamName7(DependencyObject element) => (string)element.GetValue(ParamName7Property); + public static void SetParamName8(DependencyObject element, string value) => element.SetValue(ParamName8Property, value); public static string GetParamName8(DependencyObject element) => (string)element.GetValue(ParamName8Property); + + + #endregion + + + + + private static void OnXamlScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not FrameworkElement fe) + return; + + //if (e.NewValue is not Xaml xaml) + // return; + + // 绑定上下文 + //BindLetsToContext(fe, xaml); + var trigger = GetTriggerType(fe); + fe.Loaded += (_, _) => + { + switch (trigger) + { + case XamlScriptTriggerType.Focus: + fe.GotFocus += (_, _) => RunScript(fe); + fe.LostFocus += (_, _) => RunScript(fe); + break; + + case XamlScriptTriggerType.Property: + AttachPropertyTrigger(fe); + break; + + case XamlScriptTriggerType.Event: + HookEvent(fe); + break; + } + + // 动态绑定 Let 到 DataContent + //BindLetsToDataContent(fe, xaml); + if (GetTriggerType(fe) == XamlScriptTriggerType.Loaded) + RunScript(fe); + }; + + + } + + + + + + private static void AttachPropertyTrigger(FrameworkElement fe) + { + var propName = GetTriggerName(fe); + if (string.IsNullOrWhiteSpace(propName)) + return; + + DependencyPropertyDescriptor dpd = + DependencyPropertyDescriptor.FromName(propName, fe.GetType(), fe.GetType()); + + if (dpd != null) + { + dpd.AddValueChanged(fe, (_, _) => RunScript(fe)); + } + else + { + // 非 DependencyProperty,监听普通属性 + var prop = fe.GetType().GetProperty(propName); + if (prop != null) + { + if (fe is INotifyPropertyChanged notifier) + { + notifier.PropertyChanged += (s, ev) => + { + if (ev.PropertyName == propName) + RunScript(fe); + }; + } + } + } + } + + private static void HookEvent(FrameworkElement fe) + { + var eventName = GetTriggerName(fe); + if (string.IsNullOrEmpty(eventName)) + { + return; + } + var evt = fe.GetType().GetEvent(eventName, BindingFlags.Instance | BindingFlags.Public); + if (evt == null) + { + Debug.WriteLine($"找不到事件 {eventName} 于 {fe.GetType().Name}"); + return; + } + + // 动态创建一个与事件签名匹配的委托 + var handlerMethod = typeof(XScript).GetMethod(nameof(OnEventRaised), + BindingFlags.NonPublic | BindingFlags.Static); + + if (handlerMethod == null) + return; + + var handler = Delegate.CreateDelegate(evt.EventHandlerType, handlerMethod); + evt.AddEventHandler(fe, handler); + + // 将 fe 和 xaml 映射保存,方便在回调时取出上下文 + //_eventContext[fe] = xaml; + } + //private static readonly Dictionary _eventContext = new(); + + private static void OnEventRaised(object sender, EventArgs e) + { + if (sender is FrameworkElement fe) + { + //&& _eventContext.TryGetValue(fe, out var xaml) + RunScript(fe); + } + } + + private static async void RunScript(FrameworkElement fe) + { + try + { + var result = await ExecuteScriptAsync(fe); + fe.SetValue(ReturnProperty, result); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + private static (string?, object?) GetGetParamFunc(FrameworkElement fe, int index) + { + Func getNamefunc = index switch + { + 1 => GetParamName1, + 2 => GetParamName2, + 3 => GetParamName3, + 4 => GetParamName4, + 5 => GetParamName5, + 6 => GetParamName6, + 7 => GetParamName7, + 8 => GetParamName8, + _ => throw new NotImplementedException() + }; + + Func getDatafunc = index switch + { + 1 => GetParamData1, + 2 => GetParamData2, + 3 => GetParamData3, + 4 => GetParamData4, + 5 => GetParamData5, + 6 => GetParamData6, + 7 => GetParamData7, + 8 => GetParamData8, + _ => throw new NotImplementedException() + }; + DependencyProperty paramDataProperty = index switch + { + 1 => ParamData1Property, + 2 => ParamData2Property, + 3 => ParamData3Property, + 4 => ParamData4Property, + 5 => ParamData5Property, + 6 => ParamData6Property, + 7 => ParamData7Property, + 8 => ParamData8Property, + _ => throw new NotImplementedException() + }; + var d1 = GetParamData1(fe); + var userControl = FindVisualParent(fe, typeof(UserControl)); + var value = GetBindingValue(fe, paramDataProperty, fe.DataContext); + var name = getNamefunc?.Invoke(fe); + var data = getDatafunc?.Invoke(fe); + var letData = fe.GetValue(paramDataProperty); + var datacontext = fe.DataContext; + var d = fe.GetValue(paramDataProperty); + return (name, data); + } + + /// + /// 获取绑定值 + /// + /// + /// + /// + /// + private static object? GetBindingValue(FrameworkElement fe, DependencyProperty paramDataProperty, object dataContext) + { + + //return fe.GetValue(paramDataProperty); + + var bindingExpr = BindingOperations.GetBindingExpression(fe, paramDataProperty); + if(bindingExpr is not null) + { + // 取原始绑定 + Binding oldBinding = bindingExpr.ParentBinding; + + //var rs = oldBinding.RelativeSource; + // 创建新绑定,复制原绑定设置 + var newBinding = new Binding + { + Path = oldBinding.Path, + Mode = oldBinding.Mode, + UpdateSourceTrigger = oldBinding.UpdateSourceTrigger, + Converter = oldBinding.Converter, + ConverterParameter = oldBinding.ConverterParameter, + ConverterCulture = oldBinding.ConverterCulture, + Source = dataContext + }; + + // 重新应用 + BindingOperations.SetBinding(fe,paramDataProperty, newBinding); + var data = fe.GetValue(paramDataProperty); + return data; + } + return null; + } + + + private static async Task ExecuteScriptAsync(FrameworkElement fe) + { + var script = GetXamlScript(fe); + if (script is null || string.IsNullOrWhiteSpace(script.ScriptContent)) + { + Debug.WriteLine($"[{fe.Name}] 脚本为空跳过执行 ({DateTime.Now:T})"); + return null; + } + Debug.WriteLine($"[{fe.Name}] 执行脚本 ({DateTime.Now:T})"); + + + + + IScriptInvokeContext invokeContext = new ScriptInvokeContext(); + Dictionary letTypes = new Dictionary(); + + for (var i = 1; i <= 8; i++) + { + (var name, var data) = GetGetParamFunc(fe, i); + if (name is null || data is null + || string.IsNullOrEmpty(name)) + { + continue; + } + var type = data.GetType(); + letTypes[name] = type; + invokeContext.SetVarValue(name, data); + + } + + + + SereinScript sereinScript = new SereinScript(); + sereinScript.ParserScript(script.ScriptContent, letTypes); + var result = await sereinScript.InterpreterAsync(invokeContext); + + Debug.WriteLine("脚本执行结束\n"); + return result; + + } + /// + /// 视觉树查找控件 + /// + /// + /// + /// + private static DependencyObject? FindVisualParent(DependencyObject child, Type targetType) + { + DependencyObject? current = child; + + while (current != null) + { + current = VisualTreeHelper.GetParent(current); + if (current != null && targetType.IsAssignableFrom(current.GetType())) + return current; + } + return null; + } + } + +} + + diff --git a/Workbench/Temp/Xaml.cs b/Workbench/Temp/Xaml.cs new file mode 100644 index 0000000..973ebd3 --- /dev/null +++ b/Workbench/Temp/Xaml.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Markup; +using System.Windows; + +namespace Serein.Workbench.Temp +{ +#if false + /// + /// + /// + [ContentProperty(nameof(Script))] + public class Xaml : FrameworkElement + { + public Xaml() + { + Lets = new ObservableCollection(); + } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ObservableCollection Lets { get; } + + public XamlScript Script { get; set; } + + /// 查找优先级 + public static readonly DependencyProperty TriggerTargetProperty = + DependencyProperty.RegisterAttached( + "TriggerTarget", + typeof(string), + typeof(XamlScript), + new PropertyMetadata("")); + + + /// + /// 当 TriggerType = Event 时, 指定事件名称 + /// 当 TriggerType = PropertyChanged 时, 指定属性名称 + /// + public static void SetTriggerTarget(DependencyObject element, string value) => element.SetValue(TriggerTargetProperty, value); + + /// + /// 当 TriggerType = Event 时, 获取事件名称 + /// 当 TriggerType = PropertyChanged 时, 获取属性名称 + /// + public static string GetTriggerTarget(DependencyObject element) => (string)element.GetValue(TriggerTargetProperty); + + + + /// 脚本返回结果,可用于外部绑定 + public static readonly DependencyProperty ParamDatasProperty = + DependencyProperty.RegisterAttached( + "ParamDatas", + typeof(ObservableCollection), + typeof(XamlScript), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); + + + public static void SetParamDatas(DependencyObject element, ObservableCollection value) => element.SetValue(ParamDatasProperty, value); + public static ObservableCollection GetParamDatas(DependencyObject element) => (ObservableCollection)element.GetValue(ParamDatasProperty); + + + public static readonly DependencyProperty ParamNamesProperty = + DependencyProperty.RegisterAttached( + "ParamNames", + typeof(ObservableCollection), + typeof(XamlScript), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); + + + public static void SetParamNames(DependencyObject element, ObservableCollection value) => element.SetValue(ParamNamesProperty, value); + public static ObservableCollection GetParamNames(DependencyObject element) => (ObservableCollection)element.GetValue(ParamNamesProperty); + } + + + public class XamlLet : FrameworkElement + { + + public new string? Name + { + get => (string?)GetValue(NameProperty); + set => SetValue(NameProperty, value); + } + + public new static readonly DependencyProperty NameProperty = + DependencyProperty.Register(nameof(Name), typeof(string), typeof(XamlLet), new PropertyMetadata(null)); + + /// + /// 可选类型限定 + /// + public Type? Type + { + get => (Type?)GetValue(TypeProperty); + set => SetValue(TypeProperty, value); + } + + public static readonly DependencyProperty TypeProperty = + DependencyProperty.Register(nameof(Type), typeof(Type), typeof(XamlLet), new PropertyMetadata(null)); + + /// 查找优先级 + public static readonly DependencyProperty ValueProperty = + DependencyProperty.RegisterAttached( + "Value", + typeof(object), + typeof(XamlScript), + new PropertyMetadata(null)); + + public static void SetValue(DependencyObject element, object value) => element.SetValue(ValueProperty, value); + + public static object GetValue(DependencyObject element) => (object)element.GetValue(ValueProperty); + + + ///// + ///// 可以是 BindingExpression、字符串、任意对象 + ///// + //public object Value + //{ + // get => (object)GetValue(ValueProperty); + // set => SetValue(ValueProperty, value); + //} + + //public static readonly DependencyProperty ValueProperty = + // DependencyProperty.Register(nameof(Value), typeof(object), typeof(XamlLet), new PropertyMetadata(null)); + + //public override string ToString() => $"Let {Name} = {Value}"; + + + } + + + [ContentProperty(nameof(Content))] + public class XamlScript : FrameworkElement + { + /// + /// 脚本节点内容 + /// + public string? Content { get; set; } + + public override string ToString() => Content ?? string.Empty; + } +#endif + +} diff --git a/Workbench/Temp/XamlScript.cs b/Workbench/Temp/XamlScript.cs new file mode 100644 index 0000000..78e5280 --- /dev/null +++ b/Workbench/Temp/XamlScript.cs @@ -0,0 +1,613 @@ +using Serein.Script; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows; +using System.Configuration; +using System.ComponentModel.DataAnnotations; +using System.Windows.Markup; +using System.Reactive; + +namespace Serein.Workbench.Temp +{ + [ContentProperty(nameof(XamlScript.Content))] + public class XamlScript : FrameworkElement + { + /// + /// 脚本节点内容 + /// + public string? Content { get; set; } + + public override string ToString() => Content ?? string.Empty; + } + + public enum XamlScriptTriggerType + { + /// + /// 初始化时触发 + /// + Loaded, + /// + /// 属性变更触发 + /// + Property, + /// + /// 指定事件触发 + /// + Event, + /// + /// 获得/失去焦点触发 + /// + Focus + } + + /*public enum FindPriorityType + { + /// + /// 不查找 + /// + None, + /// + /// 视觉优先 + /// + Visual, + /// + /// 逻辑优先 + /// + Logical, + /// + /// 仅视觉 + /// + VisualOnly, + /// + /// 仅逻辑 + /// + LogicalOnly, + }*/ + + + + public static class ScriptMethod + { + public static void debug(object value) + { + Debug.WriteLine(value); + } + } + + + public static class XScript + { + static XScript() + { + LoadType(typeof(Serein.Library.ScriptBaseFunc)); + LoadType(typeof(ScriptMethod)); + } + + private static void LoadType(Type type) + { + // 获取方法 + var tempMethods = type.GetMethods().Where(method => + method.IsStatic && + !(method.Name.Equals("GetHashCode") + || method.Name.Equals("Equals") + || method.Name.Equals("ToString") + || method.Name.Equals("GetType") + )).Select(method => (method.Name, method)).ToArray(); + // 挂在方法 + foreach ((string name, MethodInfo method) item in tempMethods) + { + SereinScript.AddStaticFunction(item.name, item.method); + } + } + + #region 附加属性定义 + + + public static readonly DependencyProperty XamlScriptProperty = + DependencyProperty.RegisterAttached( + "XamlScript", + typeof(XamlScript), + typeof(XScript), + new PropertyMetadata(null, OnXamlScriptChanged)); + + /// 触发类型 + public static readonly DependencyProperty TriggerTypeProperty = + DependencyProperty.RegisterAttached( + "TriggerType", + typeof(XamlScriptTriggerType), + typeof(XScript), + new PropertyMetadata(XamlScriptTriggerType.Loaded)); + + /// 触发属性名称 + public static readonly DependencyProperty TriggerNameProperty = + DependencyProperty.RegisterAttached( + "TriggerName", + typeof(string), + typeof(XScript), + new PropertyMetadata("")); + + + + /// 脚本返回结果,可用于外部绑定 + public static readonly DependencyProperty ReturnProperty = + DependencyProperty.RegisterAttached( + "Return", + typeof(object), + typeof(XScript), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); + + + /// 查找DataContent来源类型 + public static readonly DependencyProperty FindTypeProperty = + DependencyProperty.RegisterAttached("FindType", + typeof(Type), + typeof(XScript), + new PropertyMetadata(null)); + /*/// 查找优先级 + public static readonly DependencyProperty FindPriorityProperty = + DependencyProperty.RegisterAttached( + "FindPriority", + typeof(FindPriorityType), + typeof(XScript), + new PropertyMetadata(FindPriorityType.Visual));*/ + + /* /// 是否使用 + public static readonly DependencyProperty UseDataContextProperty = + DependencyProperty.RegisterAttached( + "UseDataContext", + typeof(bool), + typeof(XScript), + new PropertyMetadata(true));*/ + + + + public static void SetFindType(DependencyObject element, Type value) => element.SetValue(FindTypeProperty, value); + public static Type GetFindType(DependencyObject element) => (Type)element.GetValue(FindTypeProperty); + + /* public static void SetFindPriority(DependencyObject element, FindPriorityType value) => element.SetValue(FindPriorityProperty, value); + public static FindPriorityType GetFindPriority(DependencyObject element) => (FindPriorityType)element.GetValue(FindPriorityProperty);*/ + + public static void SetXamlScript(DependencyObject element, XamlScript value) => element.SetValue(XamlScriptProperty, value); + public static XamlScript GetXamlScript(DependencyObject element) => (XamlScript)element.GetValue(XamlScriptProperty); + + public static void SetTriggerType(DependencyObject element, XamlScriptTriggerType value) => element.SetValue(TriggerTypeProperty, value); + public static XamlScriptTriggerType GetTriggerType(DependencyObject element) => (XamlScriptTriggerType)element.GetValue(TriggerTypeProperty); + + public static void SetTriggerName(DependencyObject element, string value) => element.SetValue(TriggerNameProperty, value); + public static string GetTriggerName(DependencyObject element) => (string)element.GetValue(TriggerNameProperty); + + public static void SetReturn(DependencyObject element, object value) => element.SetValue(ReturnProperty, value); + public static object GetReturn(DependencyObject element) => element.GetValue(ReturnProperty); + + + /* public static void SetUseDataContext(DependencyObject element, bool value) => element.SetValue(UseDataContextProperty, value); + public static bool GetUseDataContext(DependencyObject element) => (bool)element.GetValue(UseDataContextProperty);*/ + + + public static readonly DependencyProperty ParamData1Property = DependencyProperty.RegisterAttached("ParamData1", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData2Property = DependencyProperty.RegisterAttached("ParamData2", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData3Property = DependencyProperty.RegisterAttached("ParamData3", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData4Property = DependencyProperty.RegisterAttached("ParamData4", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData5Property = DependencyProperty.RegisterAttached("ParamData5", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData6Property = DependencyProperty.RegisterAttached("ParamData6", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData7Property = DependencyProperty.RegisterAttached("ParamData7", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static readonly DependencyProperty ParamData8Property = DependencyProperty.RegisterAttached("ParamData8", typeof(object), typeof(XScript), new PropertyMetadata(Unit.Default)); + public static void SetParamData1(DependencyObject element, object value) => element.SetValue(ParamData1Property, value); public static object GetParamData1(DependencyObject element) => element.GetValue(ParamData1Property); + public static void SetParamData2(DependencyObject element, object value) => element.SetValue(ParamData2Property, value); public static object GetParamData2(DependencyObject element) => element.GetValue(ParamData2Property); + public static void SetParamData3(DependencyObject element, object value) => element.SetValue(ParamData3Property, value); public static object GetParamData3(DependencyObject element) => element.GetValue(ParamData3Property); + public static void SetParamData4(DependencyObject element, object value) => element.SetValue(ParamData4Property, value); public static object GetParamData4(DependencyObject element) => element.GetValue(ParamData4Property); + public static void SetParamData5(DependencyObject element, object value) => element.SetValue(ParamData5Property, value); public static object GetParamData5(DependencyObject element) => element.GetValue(ParamData5Property); + public static void SetParamData6(DependencyObject element, object value) => element.SetValue(ParamData6Property, value); public static object GetParamData6(DependencyObject element) => element.GetValue(ParamData6Property); + public static void SetParamData7(DependencyObject element, object value) => element.SetValue(ParamData7Property, value); public static object GetParamData7(DependencyObject element) => element.GetValue(ParamData7Property); + public static void SetParamData8(DependencyObject element, object value) => element.SetValue(ParamData8Property, value); public static object GetParamData8(DependencyObject element) => element.GetValue(ParamData8Property); + + + public static readonly DependencyProperty ParamName1Property = DependencyProperty.RegisterAttached("ParamName1", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName2Property = DependencyProperty.RegisterAttached("ParamName2", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName3Property = DependencyProperty.RegisterAttached("ParamName3", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName4Property = DependencyProperty.RegisterAttached("ParamName4", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName5Property = DependencyProperty.RegisterAttached("ParamName5", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName6Property = DependencyProperty.RegisterAttached("ParamName6", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName7Property = DependencyProperty.RegisterAttached("ParamName7", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static readonly DependencyProperty ParamName8Property = DependencyProperty.RegisterAttached("ParamName8", typeof(string), typeof(XScript), new PropertyMetadata("")); + public static void SetParamName1(DependencyObject element, string value) => element.SetValue(ParamName1Property, value); public static string GetParamName1(DependencyObject element) => (string)element.GetValue(ParamName1Property); + public static void SetParamName2(DependencyObject element, string value) => element.SetValue(ParamName2Property, value); public static string GetParamName2(DependencyObject element) => (string)element.GetValue(ParamName2Property); + public static void SetParamName3(DependencyObject element, string value) => element.SetValue(ParamName3Property, value); public static string GetParamName3(DependencyObject element) => (string)element.GetValue(ParamName3Property); + public static void SetParamName4(DependencyObject element, string value) => element.SetValue(ParamName4Property, value); public static string GetParamName4(DependencyObject element) => (string)element.GetValue(ParamName4Property); + public static void SetParamName5(DependencyObject element, string value) => element.SetValue(ParamName5Property, value); public static string GetParamName5(DependencyObject element) => (string)element.GetValue(ParamName5Property); + public static void SetParamName6(DependencyObject element, string value) => element.SetValue(ParamName6Property, value); public static string GetParamName6(DependencyObject element) => (string)element.GetValue(ParamName6Property); + public static void SetParamName7(DependencyObject element, string value) => element.SetValue(ParamName7Property, value); public static string GetParamName7(DependencyObject element) => (string)element.GetValue(ParamName7Property); + public static void SetParamName8(DependencyObject element, string value) => element.SetValue(ParamName8Property, value); public static string GetParamName8(DependencyObject element) => (string)element.GetValue(ParamName8Property); + + + #endregion + + + + + //private static void OnDataContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + //{ + // if (d is not FrameworkElement fe) + // return; + + // if (e.NewValue is not Xaml xaml) + // return; + // BindLetsToDataContent(fe, xaml); + //} + + private static void OnXamlScriptChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not FrameworkElement fe) + return; + + //if (e.NewValue is not Xaml xaml) + // return; + + // 绑定上下文 + //BindLetsToContext(fe, xaml); + var trigger = GetTriggerType(fe); + fe.Loaded += (_, _) => + { + switch (trigger) + { + case XamlScriptTriggerType.Focus: + fe.GotFocus += (_, _) => RunScript(fe); + fe.LostFocus += (_, _) => RunScript(fe); + break; + + case XamlScriptTriggerType.Property: + AttachPropertyTrigger(fe); + break; + + case XamlScriptTriggerType.Event: + HookEvent(fe); + break; + } + + // 动态绑定 Let 到 DataContent + //BindLetsToDataContent(fe, xaml); + if (GetTriggerType(fe) == XamlScriptTriggerType.Loaded) + RunScript(fe); + }; + + + } + + /*private static void BindLetsToDataContent(FrameworkElement fe, Xaml xaml) + { + if (fe == null || xaml?.Lets == null) return; + + // 获取 DataContent + var dataContext = GetDataContent(fe); + if (dataContext is null) + { + dataContext = fe.DataContext; + } + if (dataContext is null) + { + return; + } + foreach (var let in xaml.Lets) + { + if (let == null) continue; + + var bindingExpr = BindingOperations.GetBindingExpression(let, XamlLet.ValueProperty); + if (bindingExpr != null) + { + // 取原始绑定 + var oldBinding = bindingExpr.ParentBinding; + + // 创建新绑定,复制原绑定设置 + var newBinding = new Binding + { + Path = oldBinding.Path, + Mode = oldBinding.Mode, + UpdateSourceTrigger = oldBinding.UpdateSourceTrigger, + Converter = oldBinding.Converter, + ConverterParameter = oldBinding.ConverterParameter, + ConverterCulture = oldBinding.ConverterCulture, + Source = dataContext // ? 新数据源 + }; + + // 重新应用 + BindingOperations.SetBinding(fe, XamlLet.ValueProperty, newBinding); + var data = fe.GetValue(XamlLet.ValueProperty); + } + + } + } +*/ + + + + + #region 脚本执行逻辑 + private static void AttachPropertyTrigger(FrameworkElement fe) + { + var propName = GetTriggerName(fe); + if (string.IsNullOrWhiteSpace(propName)) + return; + + DependencyPropertyDescriptor dpd = + DependencyPropertyDescriptor.FromName(propName, fe.GetType(), fe.GetType()); + + if (dpd != null) + { + dpd.AddValueChanged(fe, (_, _) => RunScript(fe)); + } + else + { + // 非 DependencyProperty,监听普通属性 + var prop = fe.GetType().GetProperty(propName); + if (prop != null) + { + if (fe is INotifyPropertyChanged notifier) + { + notifier.PropertyChanged += (s, ev) => + { + if (ev.PropertyName == propName) + RunScript(fe); + }; + } + } + } + } + + private static void HookEvent(FrameworkElement fe) + { + var eventName = GetTriggerName(fe); + if (string.IsNullOrEmpty(eventName)) + { + return; + } + var evt = fe.GetType().GetEvent(eventName, BindingFlags.Instance | BindingFlags.Public); + if (evt == null) + { + Debug.WriteLine($"找不到事件 {eventName} 于 {fe.GetType().Name}"); + return; + } + + // 动态创建一个与事件签名匹配的委托 + var handlerMethod = typeof(XScript).GetMethod(nameof(OnEventRaised), + BindingFlags.NonPublic | BindingFlags.Static); + + if (handlerMethod == null) + return; + + var handler = Delegate.CreateDelegate(evt.EventHandlerType, handlerMethod); + evt.AddEventHandler(fe, handler); + + // 将 fe 和 xaml 映射保存,方便在回调时取出上下文 + //_eventContext[fe] = xaml; + } + //private static readonly Dictionary _eventContext = new(); + + private static void OnEventRaised(object sender, EventArgs e) + { + if (sender is FrameworkElement fe) + { + //&& _eventContext.TryGetValue(fe, out var xaml) + RunScript(fe); + } + } + + private static async void RunScript(FrameworkElement fe) + { + try + { + var result = await ExecuteScriptAsync(fe); + fe.SetValue(ReturnProperty, result); + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + + private static (string?, object?) GetGetParamFunc(FrameworkElement fe, int index) + { + Func getNamefunc = index switch + { + 1 => GetParamName1, + 2 => GetParamName2, + 3 => GetParamName3, + 4 => GetParamName4, + 5 => GetParamName5, + 6 => GetParamName6, + 7 => GetParamName7, + 8 => GetParamName8, + _ => throw new NotImplementedException() + }; + + Func getDatafunc = index switch + { + 1 => GetParamData1, + 2 => GetParamData2, + 3 => GetParamData3, + 4 => GetParamData4, + 5 => GetParamData5, + 6 => GetParamData6, + 7 => GetParamData7, + 8 => GetParamData8, + _ => throw new NotImplementedException() + }; + var name = getNamefunc?.Invoke(fe); + var data = getDatafunc?.Invoke(fe); + return (name, data); + } + + private static async Task ExecuteScriptAsync(FrameworkElement fe) + { + var script = GetXamlScript(fe); + if (script is null || string.IsNullOrWhiteSpace(script.Content)) + { + Debug.WriteLine($"[{fe.Name}] 脚本为空跳过执行 ({DateTime.Now:T})"); + return null; + } + Debug.WriteLine($"[{fe.Name}] 执行脚本 ({DateTime.Now:T})"); + + + + + IScriptInvokeContext invokeContext = new ScriptInvokeContext(); + Dictionary letTypes = new Dictionary(); + + for(var i = 1; i <= 8; i++) + { + (var name,var data) = GetGetParamFunc(fe,i); + if(name is null || data is null + || string.IsNullOrEmpty(name)) + { + continue; + } + var type = data.GetType(); + letTypes[name] = type; + invokeContext.SetVarValue(name, data); + + } + + + + SereinScript sereinScript = new SereinScript(); + sereinScript.ParserScript(script.Content, letTypes); + var result = await sereinScript.InterpreterAsync(invokeContext); + + Debug.WriteLine("脚本执行结束\n"); + return result; + + } + + /// + /// 获取绑定值 + /// + /// + /// + /// + /// + /* private static object? GetBindingValue(FrameworkElement fe, XamlLet let, object dataContext) + { + + var bindingExpr = BindingOperations.GetBindingExpression(let, XamlLet.ValueProperty); + if (bindingExpr != null) + { + // 取原始绑定 + Binding oldBinding = bindingExpr.ParentBinding; + + //var rs = oldBinding.RelativeSource; + // 创建新绑定,复制原绑定设置 + var newBinding = new Binding + { + Path = oldBinding.Path, + Mode = oldBinding.Mode, + UpdateSourceTrigger = oldBinding.UpdateSourceTrigger, + Converter = oldBinding.Converter, + ConverterParameter = oldBinding.ConverterParameter, + ConverterCulture = oldBinding.ConverterCulture, + Source = dataContext + }; + + // 重新应用 + BindingOperations.SetBinding(fe, XamlLet.ValueProperty, newBinding); + var data = fe.GetValue(XamlLet.ValueProperty); + return data; + } + return null; + }*/ + /*private static FrameworkElement GetParent(FrameworkElement fe) + { + var type = GetFindType(fe); + if (type is null) + { + return fe; + } + var priority = GetFindPriority(fe); + + if (priority == FindPriorityType.VisualOnly) + { + if (FindVisualParent(fe, type) is FrameworkElement element) + { + return element; + } + } + else if (priority == FindPriorityType.LogicalOnly) + { + if (FindLogicalParent(fe, type) is FrameworkElement element) + { + return element; + } + } + else if (priority == FindPriorityType.Visual) + { + if (FindVisualParent(fe, type) is FrameworkElement element) + { + return element; + } + if (FindVisualParent(fe, type) is FrameworkElement element2) + { + return element2; + } + } + else if (priority == FindPriorityType.Logical) + { + if (FindVisualParent(fe, type) is FrameworkElement element) + { + return element; + } + if (FindVisualParent(fe, type) is FrameworkElement element2) + { + return element2; + } + } + return fe; + }*/ + + + /// + /// 视觉树查找控件 + /// + /// + /// + /// + private static DependencyObject? FindVisualParent(DependencyObject child, Type targetType) + { + DependencyObject? current = child; + + while (current != null) + { + current = VisualTreeHelper.GetParent(current); + if (current != null && targetType.IsAssignableFrom(current.GetType())) + return current; + } + return null; + } + + /// + /// 逻辑树查找控件 + /// + /// + /// + /// + private static DependencyObject? FindLogicalParent(DependencyObject child, Type targetType) + { + DependencyObject? current = child; + + while (current != null) + { + current = LogicalTreeHelper.GetParent(current); + if (current != null && targetType.IsAssignableFrom(current.GetType())) + return current; + } + return null; + } + #endregion + } + +}