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