From 75a9aa846255ecfdbe9a97aef6f6fdd94a854c90 Mon Sep 17 00:00:00 2001 From: zengwenjie <1663900244@qq.com> Date: Tue, 16 Sep 2025 21:33:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E6=A1=86=E6=9E=B6=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DeedyDesigner/Deedy.Activity/ActionViewer.cs | 765 ++++++++++++++++-- .../CombineRule_AllowTypeAttribute.cs | 23 + .../CombineRule_ClearInheritedAttribute.cs | 16 + .../CombineRule_RejectTypeAttribute.cs | 23 + .../Attribute/IconKeyAttribute.cs | 30 + DeedyDesigner/Deedy.Activity/BasalAction.cs | 16 + .../Contract/Entities/DragDropData.cs | 14 + .../Contract/Entities/LogInfo.cs | 12 +- .../Contract/Enums/ExitlinePosition.cs | 7 +- .../Contract/Interface/IContainerElement.cs | 60 ++ .../Interface/ICriticalZoneManageable.cs | 14 + .../Contract/Interface/IExitlineManageable.cs | 13 + .../Controller/ActivityRepository.cs | 37 + DeedyDesigner/Deedy.Activity/DeedyHelper.cs | 87 -- DeedyDesigner/Deedy.Activity/Helper.cs | 216 +++++ .../Deedy.Activity/IActionElement.cs | 2 + DeedyDesigner/Deedy.Activity/IActionViewer.cs | 32 +- .../Deedy.Activity/Resources/ThemeKeys.cs | 24 + .../Resources/ThemeResources.cs | 15 + .../Deedy.Activity/Themes/Generic.xaml | 19 +- .../Deedy.Activity/Themes/ThemeResources.xaml | 10 + .../Viewer/ViewerStateDecorator.cs | 56 ++ .../Viewer/ViewerStyleSelector.cs | 75 ++ 23 files changed, 1395 insertions(+), 171 deletions(-) create mode 100644 DeedyDesigner/Deedy.Activity/Attribute/CombineRule_AllowTypeAttribute.cs create mode 100644 DeedyDesigner/Deedy.Activity/Attribute/CombineRule_ClearInheritedAttribute.cs create mode 100644 DeedyDesigner/Deedy.Activity/Attribute/CombineRule_RejectTypeAttribute.cs create mode 100644 DeedyDesigner/Deedy.Activity/Attribute/IconKeyAttribute.cs create mode 100644 DeedyDesigner/Deedy.Activity/Contract/Entities/DragDropData.cs create mode 100644 DeedyDesigner/Deedy.Activity/Contract/Interface/ICriticalZoneManageable.cs create mode 100644 DeedyDesigner/Deedy.Activity/Contract/Interface/IExitlineManageable.cs create mode 100644 DeedyDesigner/Deedy.Activity/Controller/ActivityRepository.cs delete mode 100644 DeedyDesigner/Deedy.Activity/DeedyHelper.cs create mode 100644 DeedyDesigner/Deedy.Activity/Helper.cs create mode 100644 DeedyDesigner/Deedy.Activity/Resources/ThemeKeys.cs create mode 100644 DeedyDesigner/Deedy.Activity/Resources/ThemeResources.cs create mode 100644 DeedyDesigner/Deedy.Activity/Themes/ThemeResources.xaml create mode 100644 DeedyDesigner/Deedy.Activity/Viewer/ViewerStateDecorator.cs create mode 100644 DeedyDesigner/Deedy.Activity/Viewer/ViewerStyleSelector.cs diff --git a/DeedyDesigner/Deedy.Activity/ActionViewer.cs b/DeedyDesigner/Deedy.Activity/ActionViewer.cs index d3595f2..592659e 100644 --- a/DeedyDesigner/Deedy.Activity/ActionViewer.cs +++ b/DeedyDesigner/Deedy.Activity/ActionViewer.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; @@ -19,41 +21,40 @@ using System.Windows.Shapes; namespace Deedy.Activity { /// - /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。 - /// - /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。 - /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 - /// 元素中: - /// - /// xmlns:MyNamespace="clr-namespace:Deedy.Design" - /// - /// - /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。 - /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 - /// 元素中: - /// - /// xmlns:MyNamespace="clr-namespace:Deedy.Design;assembly=Deedy.Design" - /// - /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用, - /// 并重新生成以避免编译错误: - /// - /// 在解决方案资源管理器中右击目标项目,然后依次单击 - /// “添加引用”->“项目”->[浏览查找并选择此项目] - /// - /// - /// 步骤 2) - /// 继续操作并在 XAML 文件中使用控件。 - /// - /// - /// + /// 用于为Action提供显示视图 /// + [IconKey(ThemeKeys.KEY_Activity_DefaultIcon)] + [TemplatePart(Name = PART_ItemsContainer, Type = typeof(ItemsControl))] + [TemplatePart(Name = PART_TitleContainer, Type = typeof(FrameworkElement))] + [TemplatePart(Name = PART_StateDecorator, Type = typeof(ViewerStateDecorator))] public class ActionViewer : Control, IActionViewer { + public const string PART_ItemsContainer = "PART_ItemsContainer"; + public const string PART_TitleContainer = "PART_TitleContainer"; + public const string PART_StateDecorator = "PART_StateDecorator"; + [AllowNull] + protected internal ItemsControl ItemsContainer; + [AllowNull] + protected internal FrameworkElement TitleContainer; + [AllowNull] + protected internal ViewerStateDecorator StateDecorator; static ActionViewer() { DefaultStyleKeyProperty.OverrideMetadata(typeof(ActionViewer), new FrameworkPropertyMetadata(typeof(ActionViewer))); } - + public ActionViewer() + { + ToolTipService.SetInitialShowDelay(this, 0); + ToolTipService.SetBetweenShowDelay(this, 0); + } + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + this.ItemsContainer = this.GetTemplateChild(PART_ItemsContainer) as ItemsControl; + this.TitleContainer = this.GetTemplateChild(PART_TitleContainer) as FrameworkElement; + this.StateDecorator = this.GetTemplateChild(PART_StateDecorator) as ViewerStateDecorator; + this.RefreshViewerState(); + } public event PropertyChangedEventHandler? PropertyChanged; /// @@ -86,60 +87,404 @@ namespace Deedy.Activity field = value; OnPropertyChanged(propertyName); return true; - } + } + [AllowNull] + public Runtime Runtime { get; protected internal set; } - public Runtime Runtime => throw new NotImplementedException(); + /// + /// 是否显示Break控制手柄 + /// + public Visibility ShowBreakHandle + { + get { return (Visibility)GetValue(ShowBreakHandleProperty); } + protected internal set { SetValue(ShowBreakHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowBreakHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowBreakHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowBreakHandleProperty = ShowBreakHandlePropertyKey.DependencyProperty; - public Visibility ShowBreakHandle => throw new NotImplementedException(); + /// + /// 是否显示重手柄 + /// + public Visibility ShowContinueHandle + { + get { return (Visibility)GetValue(ShowContinueHandleProperty); } + protected internal set { SetValue(ShowContinueHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowContinueHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowContinueHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowContinueHandleProperty = ShowContinueHandlePropertyKey.DependencyProperty; - public Visibility ShowContinueHandle => throw new NotImplementedException(); + /// + /// 是否显示退出手柄 + /// + public Visibility ShowExitHandle + { + get { return (Visibility)GetValue(ShowExitHandleProperty); } + protected internal set { SetValue(ShowExitHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowExitHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowExitHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowExitHandleProperty = ShowExitHandlePropertyKey.DependencyProperty; - public Visibility ShowExitHandle => throw new NotImplementedException(); + /// + /// 是否显示返回手柄 + /// + public Visibility ShowReturnHandle + { + get { return (Visibility)GetValue(ShowReturnHandleProperty); } + protected internal set { SetValue(ShowReturnHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowReturnHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowReturnHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowReturnHandleProperty = ShowReturnHandlePropertyKey.DependencyProperty; - public Visibility ShowReturnHandle => throw new NotImplementedException(); + /// + /// 是否显示自定义手柄 + /// + public Visibility ShowCustomizeHandle + { + get { return (Visibility)GetValue(ShowCustomizeHandleProperty); } + protected internal set { SetValue(ShowCustomizeHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowCustomizeHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowCustomizeHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowCustomizeHandleProperty = ShowCustomizeHandlePropertyKey.DependencyProperty; - public Visibility ShowCustomHandle => throw new NotImplementedException(); + /// + /// 是否显示进入区 + /// + public Visibility ShowEntryZone + { + get { return (Visibility)GetValue(ShowEntryZoneProperty); } + protected internal set { SetValue(ShowEntryZonePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowEntryZonePropertyKey = + DependencyProperty.RegisterReadOnly("ShowEntryZone", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Visible)); + public static readonly DependencyProperty ShowEntryZoneProperty = ShowEntryZonePropertyKey.DependencyProperty; - public Visibility ShowHeader => throw new NotImplementedException(); + /// + /// 是否显示退出区 + /// + public Visibility ShowLeaveZone + { + get { return (Visibility)GetValue(ShowLeaveZoneProperty); } + protected internal set { SetValue(ShowLeaveZonePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowLeaveZonePropertyKey = + DependencyProperty.RegisterReadOnly("ShowLeaveZone", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Visible)); + public static readonly DependencyProperty ShowLeaveZoneProperty = ShowLeaveZonePropertyKey.DependencyProperty; - public Visibility ShowFooter => throw new NotImplementedException(); + /// + /// 是否显示消息回显 + /// + public Visibility ShowInfoHandle + { + get { return (Visibility)GetValue(ShowInfoHandleProperty); } + protected internal set { SetValue(ShowInfoHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowInfoHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowInfoHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowInfoHandleProperty = ShowInfoHandlePropertyKey.DependencyProperty; - public Visibility ShowInfoHandle => throw new NotImplementedException(); + /// + /// 是否显示删除图标 + /// + public Visibility ShowDeleteHandle + { + get { return (Visibility)GetValue(ShowDeleteHandleProperty); } + protected internal set { SetValue(ShowDeleteHandlePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowDeleteHandlePropertyKey = + DependencyProperty.RegisterReadOnly("ShowDeleteHandle", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowDeleteHandleProperty = ShowDeleteHandlePropertyKey.DependencyProperty; - public Visibility ShowDeleteHandle => throw new NotImplementedException(); + /// + /// 显示左侧退出线 + /// + public Visibility ShowLeftExitline + { + get { return (Visibility)GetValue(ShowLeftExitlineProperty); } + protected internal set { SetValue(ShowLeftExitlinePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowLeftExitlinePropertyKey = + DependencyProperty.RegisterReadOnly("ShowLeftExitline", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowLeftExitlineProperty = ShowLeftExitlinePropertyKey.DependencyProperty; - public Visibility ShowLeftExitline => throw new NotImplementedException(); + /// + /// 显示右侧退出线 + /// + public Visibility ShowRightExitline + { + get { return (Visibility)GetValue(ShowRightExitlineProperty); } + protected internal set { SetValue(ShowRightExitlinePropertyKey, value); } + } + public static readonly DependencyPropertyKey ShowRightExitlinePropertyKey = + DependencyProperty.RegisterReadOnly("ShowRightExitline", typeof(Visibility), typeof(ActionViewer), new PropertyMetadata(Visibility.Collapsed)); + public static readonly DependencyProperty ShowRightExitlineProperty = ShowRightExitlinePropertyKey.DependencyProperty; - public Visibility ShowRightExitline => throw new NotImplementedException(); - public LogInfo InstantInfo => throw new NotImplementedException(); + /// + /// 即时消息 + /// + public LogInfo InstantInfo + { + get { return (LogInfo)GetValue(InstantInfoProperty); } + protected internal set { SetValue(InstantInfoPropertyKey, value); } + } + public static readonly DependencyPropertyKey InstantInfoPropertyKey = + DependencyProperty.RegisterReadOnly("InstantInfo", typeof(LogInfo), typeof(ActionViewer), new PropertyMetadata(LogInfo.Empty, + (d, e) => (d as ActionViewer)?.InstantInfo_PropertyChangedCallback(e))); + public static readonly DependencyProperty InstantInfoProperty = InstantInfoPropertyKey.DependencyProperty; + /// + /// 处理「ActionViewer.InstantInfo」属性变更 + /// + protected virtual void InstantInfo_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is LogInfo logInfo) + { + this.ToolTip = logInfo.ToString(); + //TODO:更新消息显示图标 + } + } - public LogInfoCollection LogInfos => throw new NotImplementedException(); + /// + /// 信息列表 + /// + public LogInfoCollection LogInfos + { + get { return (LogInfoCollection)GetValue(LogInfosProperty); } + protected internal set { SetValue(LogInfosPropertyKey, value); } + } + public static readonly DependencyPropertyKey LogInfosPropertyKey = + DependencyProperty.RegisterReadOnly("LogInfos", typeof(LogInfoCollection), typeof(ActionViewer), new PropertyMetadata(null)); + public static readonly DependencyProperty LogInfosProperty = LogInfosPropertyKey.DependencyProperty; - public uint ElementCount => throw new NotImplementedException(); + /// + /// 子元素数量 + /// + public int ElementCount + { + get { return (int)GetValue(ElementCountProperty); } + protected internal set { SetValue(ElementCountPropertyKey, value); } + } + public static readonly DependencyPropertyKey ElementCountPropertyKey = + DependencyProperty.RegisterReadOnly("ElementCount", typeof(int), typeof(ActionViewer), new PropertyMetadata(0)); + public static readonly DependencyProperty ElementCountProperty = ElementCountPropertyKey.DependencyProperty; - public bool IsSelectable => throw new NotImplementedException(); + /// + /// 是否可被选中 + /// + public bool IsSelectable + { + get { return (bool)GetValue(IsSelectableProperty); } + protected internal set { SetValue(IsSelectablePropertyKey, value); } + } + public static readonly DependencyPropertyKey IsSelectablePropertyKey = + DependencyProperty.RegisterReadOnly("IsSelectable", typeof(bool), typeof(ActionViewer), new PropertyMetadata(true)); + public static readonly DependencyProperty IsSelectableProperty = IsSelectablePropertyKey.DependencyProperty; - public bool IsSelected => throw new NotImplementedException(); + /// + /// 是否选中 + /// + public bool IsSelected + { + get { return (bool)GetValue(IsSelectedProperty); } + protected internal set { SetValue(IsSelectedPropertyKey, value); } + } + public static readonly DependencyPropertyKey IsSelectedPropertyKey = + DependencyProperty.RegisterReadOnly("IsSelected", typeof(bool), typeof(ActionViewer), new PropertyMetadata(false)); + public static readonly DependencyProperty IsSelectedProperty = IsSelectedPropertyKey.DependencyProperty; - public bool IsCanExpand => throw new NotImplementedException(); + /// + /// 是否可被展开 + /// + public bool IsExpandable + { + get { return (bool)GetValue(IsExpandableProperty); } + protected internal set { SetValue(IsExpandablePropertyKey, value); } + } + public static readonly DependencyPropertyKey IsExpandablePropertyKey = + DependencyProperty.RegisterReadOnly("IsExpandable", typeof(bool), typeof(ActionViewer), new PropertyMetadata(true)); + public static readonly DependencyProperty IsExpandableProperty = IsExpandablePropertyKey.DependencyProperty; - public bool IsExpanded => throw new NotImplementedException(); + /// + /// 是否展开 + /// + public bool IsExpanded + { + get { return (bool)GetValue(IsExpandedProperty); } + protected internal set { SetValue(IsExpandedPropertyKey, value); } + } + public static readonly DependencyPropertyKey IsExpandedPropertyKey = + DependencyProperty.RegisterReadOnly("IsExpanded", typeof(bool), typeof(ActionViewer), new PropertyMetadata(true)); + public static readonly DependencyProperty IsExpandedProperty = IsExpandedPropertyKey.DependencyProperty; - public ViewerState ViewerState => throw new NotImplementedException(); + /// + /// 是否可被拖动 + /// + public bool IsDraggable + { + get { return (bool)GetValue(IsDraggableProperty); } + protected internal set { SetValue(IsDraggablePropertyKey, value); } + } + public static readonly DependencyPropertyKey IsDraggablePropertyKey = + DependencyProperty.RegisterReadOnly("IsDraggable", typeof(bool), typeof(ActionViewer), new PropertyMetadata(true)); + public static readonly DependencyProperty IsDraggableProperty = IsDraggablePropertyKey.DependencyProperty; - public WorkMode WorkMode => throw new NotImplementedException(); - - public Brush FillBrush => throw new NotImplementedException(); + /// + /// 是否正在拖动 + /// + public bool IsDragging + { + get { return (bool)GetValue(IsDraggingProperty); } + protected internal set { SetValue(IsDraggingPropertyKey, value); } + } + public static readonly DependencyPropertyKey IsDraggingPropertyKey = + DependencyProperty.RegisterReadOnly("IsDragging", typeof(bool), typeof(ActionViewer), new PropertyMetadata(false)); + public static readonly DependencyProperty IsDraggingProperty = IsDraggingPropertyKey.DependencyProperty; - public Brush StrokeBrush => throw new NotImplementedException(); + /// + /// 视图状态 + /// + public ViewerState ViewerState + { + get { return (ViewerState)GetValue(ViewerStateProperty); } + protected internal set { SetValue(ViewerStatePropertyKey, value); } + } + public static readonly DependencyPropertyKey ViewerStatePropertyKey = + DependencyProperty.RegisterReadOnly("ViewerState", typeof(ViewerState), typeof(ActionViewer), new PropertyMetadata(ViewerState.Normal, + (d, e) => (d as ActionViewer)?.ViewerState_PropertyChangedCallback(e))); + public static readonly DependencyProperty ViewerStateProperty = ViewerStatePropertyKey.DependencyProperty; + /// + /// 处理「ActionViewer.ViewerState」属性变更 + /// + protected virtual void ViewerState_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + this.StyleSelector?.SelectStyle(this.ActionElement, this); + } - public double StrokeThickness => throw new NotImplementedException(); + /// + /// 工作模式:非设计模式下不允许拖放操作;编辑、运行、回显三种模式不可相互切换,但可以与等待和预览状态切换。 + /// + public WorkMode WorkMode + { + get { return (WorkMode)GetValue(WorkModeProperty); } + protected internal set { SetValue(WorkModePropertyKey, value); } + } + public static readonly DependencyPropertyKey WorkModePropertyKey = + DependencyProperty.RegisterReadOnly("WorkMode", typeof(WorkMode), typeof(ActionViewer), new PropertyMetadata(WorkMode.Waiting)); + public static readonly DependencyProperty WorkModeProperty = WorkModePropertyKey.DependencyProperty; - public Thickness MarginCorrection_Top => throw new NotImplementedException(); + /// + /// 填充画刷 + /// + public Brush FillBrush + { + get { return (Brush)GetValue(FillBrushProperty); } + set { SetValue(FillBrushProperty, value); } + } + public static readonly DependencyProperty FillBrushProperty = + DependencyProperty.Register("FillBrush", typeof(Brush), typeof(ActionViewer), new PropertyMetadata(Brushes.Gray)); - public Thickness MarginCorrection_Bottom => throw new NotImplementedException(); + /// + /// 画线画刷 + /// + public Brush StrokeBrush + { + get { return (Brush)GetValue(StrokeBrushProperty); } + set { SetValue(StrokeBrushProperty, value); } + } + public static readonly DependencyProperty StrokeBrushProperty = + DependencyProperty.Register("StrokeBrush", typeof(Brush), typeof(ActionViewer), new PropertyMetadata(Brushes.Orange)); + /// + /// 画线宽度 + /// + public double StrokeThickness + { + get { return (double)GetValue(StrokeThicknessProperty); } + set { SetValue(StrokeThicknessProperty, value); } + } + public static readonly DependencyProperty StrokeThicknessProperty = + DependencyProperty.Register("StrokeThickness", typeof(double), typeof(ActionViewer), new PropertyMetadata(2.0, + (d, e) => (d as ActionViewer)?.StrokeThickness_PropertyChangedCallback(e))); + /// + /// 处理「ActionViewer.StrokeThickness」属性变更 + /// + protected virtual void StrokeThickness_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is double value) + { + if (value < 2) + { + this.StrokeThickness = 2; + return; + } + double halfValue = value / 2; + this.MarginCorrection_Top = new Thickness(0, halfValue, 0, 0); + this.MarginCorrection_Bottom = new Thickness(0, 0, 0, halfValue); + this.MarginCorrection_TopBottom = new Thickness(0, halfValue, 0, halfValue); + } + else this.StrokeThickness = 2; + } - public Thickness MarginCorrection_TopBottom => throw new NotImplementedException(); + /// + /// 被托管动作元素的图标 + /// + public ImageSource ElementIcon + { + get { return (ImageSource)GetValue(ElementIconProperty); } + protected internal set { SetValue(ElementIconPropertyKey, value); } + } + public static readonly DependencyPropertyKey ElementIconPropertyKey = + DependencyProperty.RegisterReadOnly("ElementIcon", typeof(ImageSource), typeof(ActionViewer), new PropertyMetadata(null)); + public static readonly DependencyProperty ElementIconProperty = ElementIconPropertyKey.DependencyProperty; + + /// + /// 视图样式选择器 + /// + [AllowNull] + public StyleSelector StyleSelector + { + get { return (StyleSelector)GetValue(StyleSelectorProperty); } + set { SetValue(StyleSelectorProperty, value); } + } + public static readonly DependencyProperty StyleSelectorProperty = + DependencyProperty.Register("StyleSelector", typeof(StyleSelector), typeof(ActionViewer), new PropertyMetadata(null)); + /// + /// 上边距修正 + /// + public Thickness MarginCorrection_Top + { + get { return (Thickness)GetValue(MarginCorrection_TopProperty); } + protected internal set { SetValue(MarginCorrection_TopPropertyKey, value); } + } + public static readonly DependencyPropertyKey MarginCorrection_TopPropertyKey = + DependencyProperty.RegisterReadOnly("MarginCorrection_Top", typeof(Thickness), typeof(ActionViewer), new PropertyMetadata(new Thickness())); + public static readonly DependencyProperty MarginCorrection_TopProperty = MarginCorrection_TopPropertyKey.DependencyProperty; + + /// + /// 下边距修正 + /// + public Thickness MarginCorrection_Bottom + { + get { return (Thickness)GetValue(MarginCorrection_BottomProperty); } + protected internal set { SetValue(MarginCorrection_BottomPropertyKey, value); } + } + public static readonly DependencyPropertyKey MarginCorrection_BottomPropertyKey = + DependencyProperty.RegisterReadOnly("MarginCorrection_Bottom", typeof(Thickness), typeof(ActionViewer), new PropertyMetadata(new Thickness())); + public static readonly DependencyProperty MarginCorrection_BottomProperty = MarginCorrection_BottomPropertyKey.DependencyProperty; + + /// + /// 上下边距修正 + /// + public Thickness MarginCorrection_TopBottom + { + get { return (Thickness)GetValue(MarginCorrection_TopBottomProperty); } + protected internal set { SetValue(MarginCorrection_TopBottomPropertyKey, value); } + } + public static readonly DependencyPropertyKey MarginCorrection_TopBottomPropertyKey = + DependencyProperty.RegisterReadOnly("MarginCorrection_TopBottom", typeof(Thickness), typeof(ActionViewer), new PropertyMetadata(new Thickness())); + public static readonly DependencyProperty MarginCorrection_TopBottomProperty = MarginCorrection_TopBottomPropertyKey.DependencyProperty; /// /// 动作节点 /// @@ -159,36 +504,334 @@ namespace Deedy.Activity protected virtual void ActionElement_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) { if (e.OldValue is IActionElement oldValue) + { oldValue.PropertyChanged -= ActionElement_PropertyChanged; + if (oldValue is ICombinedElement combinedElement) + { + this.ElementCount = 0; + combinedElement.Elements.CollectionChanged -= Elements_CollectionChanged; + } + this.ShowEntryZone = Visibility.Visible; + this.ShowLeaveZone = Visibility.Visible; + this.ShowLeftExitline = Visibility.Collapsed; + this.ShowRightExitline = Visibility.Collapsed; + this.ShowBreakHandle = Visibility.Collapsed; + this.ShowContinueHandle = Visibility.Collapsed; + this.ShowCustomizeHandle = Visibility.Collapsed; + this.ShowExitHandle = Visibility.Collapsed; + this.ShowReturnHandle = Visibility.Collapsed; + } if (e.NewValue is IActionElement newValue) { newValue.PropertyChanged += ActionElement_PropertyChanged; + + Type elementType = newValue.GetType(); + IconKeyAttribute? iconKey = elementType.GetCustomAttribute(); + if (iconKey != null) + { + ImageSource? icon = iconKey.TryFindResource(this) as ImageSource; + if (icon != null) this.ElementIcon = icon; + else + { + iconKey = this.GetType().GetCustomAttribute(); + if (iconKey != null) icon = iconKey.TryFindResource(this) as ImageSource; + + if (icon != null) this.ElementIcon = icon; + else this.ClearValue(ElementIconPropertyKey); + } + } + + if (newValue.IsLockedElement) + { + this.IsDraggable = false; + this.IsSelectable = false; + } + else + { + this.IsDraggable = true; + this.IsSelectable = true; + } + + if (newValue is ICombinedElement newCombinedElement) + { + this.IsExpandable = true; + this.ElementCount = newCombinedElement.Elements.Count; + newCombinedElement.Elements.CollectionChanged += Elements_CollectionChanged; + } + else this.IsExpandable = false; + + if (newValue is ICriticalZoneManageable criticalZoneManageable) + { + if (criticalZoneManageable.IsLeaveZoneHidden) this.ShowLeaveZone = Visibility.Collapsed; + if (criticalZoneManageable.IsEntryZoneHidden) this.ShowEntryZone = Visibility.Collapsed; + } + + if (newValue is IExitlineManageable exitlinemanageable) + { + if ((exitlinemanageable.ExitlinePosition & ExitlinePosition.LeftLower) == ExitlinePosition.LeftLower) + this.ShowLeftExitline = Visibility.Visible; + if ((exitlinemanageable.ExitlinePosition & ExitlinePosition.Rightlower) == ExitlinePosition.Rightlower) + this.ShowRightExitline = Visibility.Visible; + } + if (newValue is ILogicController logicController) + { + switch (logicController.LogicalBehavior) + { + case LogicalBehavior.Exit: this.ShowExitHandle = Visibility.Visible; break; + case LogicalBehavior.Return: this.ShowReturnHandle = Visibility.Visible; break; + case LogicalBehavior.Break: this.ShowBreakHandle = Visibility.Visible; break; + case LogicalBehavior.Continue: this.ShowContinueHandle = Visibility.Visible; break; + case LogicalBehavior.Customize: this.ShowCustomizeHandle = Visibility.Visible; break; + default: + break; + } + } //TODO:根据节点的特征与当前工作状态来判定如何处理当前视图的属性 } } - private void ActionElement_PropertyChanged(object? sender, PropertyChangedEventArgs e) + protected virtual void Elements_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (this.ActionElement is ICombinedElement combined) + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) + this.IsExpanded = true; + this.ElementCount = combined.Elements.Count; + } + } + + protected virtual void ActionElement_PropertyChanged(object? sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { //TODO:处理托管的IActionElement节点的属性变更 + case nameof(IActionElement.InstantInfo): + this.InstantInfo = this.ActionElement.InstantInfo; + break; default: break; } } public void ReadyToWorking(IElement? element = null, Output? output = null) { - throw new NotImplementedException(); + if (this.ActionElement != element && element is IActionElement action) this.ActionElement = action; + if (this.WorkMode == WorkMode.Waiting) this.WorkMode = WorkMode.Preview; } public void ReadyToEditing(Runtime runtime) { - throw new NotImplementedException(); + this.ReadyToWorking(); + this.WorkMode = WorkMode.Editing; } public void ReadyToRunning(Runtime runtime) { - throw new NotImplementedException(); + this.ReadyToWorking(); + this.WorkMode = WorkMode.Running; } + /// + /// 刷新视图样式 + /// + protected virtual void RefreshViewerState(bool isOverMe = false) + { + if (this.IsDragging) + { + if (this.IsSelected) + { + if (isOverMe) this.ViewerState = ViewerState.SelectedDragHover; + else this.ViewerState = ViewerState.Selected; + } + else + { + if (isOverMe) this.ViewerState = ViewerState.NormalDragHover; + else this.ViewerState = ViewerState.Normal; + } + } + else + { + if (this.IsSelected) + { + if (isOverMe) this.ViewerState = ViewerState.SelectedHover; + else this.ViewerState = ViewerState.Selected; + } + else + { + if (isOverMe) this.ViewerState = ViewerState.NormalHover; + else this.ViewerState = ViewerState.Normal; + } + } + } + /// + /// 检查事件源是否需要自身处理 + /// + /// 引发事件的源 + /// 只有事件源是自身,或事件源的第一个SmartView类型的祖辈是自身时才需要处理 + protected virtual bool IsEventNeedToHandle(object eventSource) + { + bool result = false; + if (eventSource is ActionViewer view && view != this) result = false; + if (eventSource is not ActionViewer && eventSource is DependencyObject dobj && this == dobj.FindAncestor()) result = true; + return result; + } + protected virtual void RemoveDragAdorner() + { } + protected virtual void UpdateDragAdorner(Dock? dock) + { } + #region 交互事件 + protected override void OnDragEnter(DragEventArgs e) + { + this.IsDragging = true; + ToolTipService.SetIsEnabled(this, false); + + base.OnDragEnter(e); + } + protected override void OnDragLeave(DragEventArgs e) + { + this.IsDragging = false; + + base.OnDragLeave(e); + } + private bool _CanDropInParent = false; + private bool _CanDropChild = false; + private DropPlacement _DropPlacement = DropPlacement.Uncertain; + protected override void OnDragOver(DragEventArgs e) + { + if (this.IsEventNeedToHandle(e.OriginalSource)) + { + this.RefreshViewerState(true); + FrameworkElement hitElement = this; + if (this.TitleContainer != null && this.TitleContainer.Visibility == Visibility.Visible) + hitElement = this.TitleContainer; + + Point currentPoint = e.GetPosition(hitElement); + if (this._CanDropInParent && (currentPoint.Y < 10 || currentPoint.Y < 10)) + { + this._DropPlacement = DropPlacement.BeforeMe; + this.UpdateDragAdorner(Dock.Top); + } + else if (this._CanDropInParent && (hitElement.ActualHeight - currentPoint.Y < 10 || hitElement.ActualWidth - currentPoint.X < 10)) + { + this._DropPlacement = DropPlacement.BehindMe; + this.UpdateDragAdorner(Dock.Bottom); + } + else if (this._CanDropChild) + { + this._DropPlacement = DropPlacement.WithinMe; + this.UpdateDragAdorner(null); + } + else + { + this._DropPlacement = DropPlacement.Rejected; + this.RemoveDragAdorner(); + } + } + else + { + this.RefreshViewerState(); + this.RemoveDragAdorner(); + } + + base.OnDragOver(e); + } + protected override void OnDrop(DragEventArgs e) + { + this.IsDragging = false; + this.RefreshViewerState(); + this.RemoveDragAdorner(); + if (this.IsEventNeedToHandle(e.OriginalSource)) + { + //TODO:发送准备放置事件,如果事件被处理则「return」放弃默认逻辑 + //注意:这里不能标记e.Handle=true;否则可能会造成视图显示状态异常 + if (e.Data.GetData(typeof(DragDropData)) is DragDropData data) + { + data.Placement = this._DropPlacement; + //TODO:执行放置操作 + } + } + + base.OnDrop(e); + } + protected override void OnMouseEnter(MouseEventArgs e) + { + base.OnMouseEnter(e); + ToolTipService.SetIsEnabled(this, true); + if (!this.IsDragging) this.RefreshViewerState(true); + } + protected override void OnMouseLeave(MouseEventArgs e) + { + base.OnMouseLeave(e); + + if (!this.IsDragging) this.RefreshViewerState(); + } + protected override void OnMouseDown(MouseButtonEventArgs e) + { + base.OnMouseDown(e); + + if (e.LeftButton == MouseButtonState.Pressed) + { + this.IsSelected = this.IsSelectable; + if (this.IsDraggable) this._DragStartPoint = e.GetPosition(this); + } + } + protected override void OnMouseUp(MouseButtonEventArgs e) + { + base.OnMouseUp(e); + + this._DragStartPoint = null; + } + protected override void OnMouseMove(MouseEventArgs e) + { + base.OnMouseMove(e); + if (this.IsDragging) return; + bool isEventNeedHandle = this.IsEventNeedToHandle(e.OriginalSource); + this.RefreshViewerState(isEventNeedHandle); + if (isEventNeedHandle) + { + if (this.ActionElement == null || this.ActionElement.IsLockedElement) return; + + var position = e.GetPosition(this); + ToolTipService.SetPlacement(this, PlacementMode.Relative); + ToolTipService.SetPlacementTarget(this, this); + ToolTipService.SetHorizontalOffset(this, position.X + 16); + ToolTipService.SetVerticalOffset(this, position.Y + 16); + } + } + private readonly object _DragLock = new(); + private Point? _DragStartPoint = null; + + protected override void OnPreviewMouseMove(MouseEventArgs e) + { + base.OnPreviewMouseMove(e); + if (!this.IsDraggable) return; + if (e.LeftButton == MouseButtonState.Pressed) + { + lock (_DragLock) + { + if (this.IsDragging || !_DragStartPoint.HasValue) return; + if (_DragStartPoint.HasValue) + { + Point currentPoint = e.GetPosition(this); + + if (Math.Abs(this._DragStartPoint.Value.X - currentPoint.X) > SystemParameters.MinimumHorizontalDragDistance + || + Math.Abs(this._DragStartPoint.Value.Y - currentPoint.Y) > SystemParameters.MinimumVerticalDragDistance) + { + //TODO:发送准备拖动事件,如果事件被响应则「return」退出原本逻辑 + + DragDropEffects dragDropEffects = DragDropEffects.Link; + if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + dragDropEffects |= DragDropEffects.Copy; + else dragDropEffects |= DragDropEffects.Move; + //TODO:构造拖动数据 + e.Handled = true; + this._DragStartPoint = null; + //TODO:启动拖动逻辑 + //DragDrop.DoDragDrop(this, data, data.dragEffect); + } + } + } + } + } + #endregion } } diff --git a/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_AllowTypeAttribute.cs b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_AllowTypeAttribute.cs new file mode 100644 index 0000000..5c04d74 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_AllowTypeAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + /// + /// 定义IElement节点允许那些节点组装到其内部,优先级低于拒绝规则 + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public class CombineRule_AllowTypeAttribute : Attribute + { + public CombineRule_AllowTypeAttribute(Type baseType, params Type[] excluded) + { + this.BaseType = baseType; + this.Excluded.AddRange(excluded); + } + public Type BaseType { get; private set; } + public List Excluded { get; private set; } = new List(); + } +} diff --git a/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_ClearInheritedAttribute.cs b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_ClearInheritedAttribute.cs new file mode 100644 index 0000000..d135c65 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_ClearInheritedAttribute.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + /// + /// 清除继承自基类的组装规则 + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class CombineRule_ClearInheritedAttribute : Attribute + { + } +} diff --git a/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_RejectTypeAttribute.cs b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_RejectTypeAttribute.cs new file mode 100644 index 0000000..a60491d --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Attribute/CombineRule_RejectTypeAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + /// + /// 定义IElement节点禁止那些节点组装到其内部,优先级高于允许规则 + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public class CombineRule_RejectTypeAttribute : Attribute + { + public CombineRule_RejectTypeAttribute(Type baseType, params Type[] excluded) + { + this.BaseType = baseType; + this.Excluded.AddRange(excluded); + } + public Type BaseType { get; private set; } + public List Excluded { get; private set; } = new List(); + } +} diff --git a/DeedyDesigner/Deedy.Activity/Attribute/IconKeyAttribute.cs b/DeedyDesigner/Deedy.Activity/Attribute/IconKeyAttribute.cs new file mode 100644 index 0000000..915461f --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Attribute/IconKeyAttribute.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Deedy.Activity +{ + /// + /// 为Activity类型定义显示图标的ResourceKey + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] + public class IconKeyAttribute : Attribute + { + public IconKeyAttribute(string resourceKey) => this.ResourceKey = resourceKey; + public string ResourceKey { get; private set; } + private ComponentResourceKey? LookupResourceKey() => ThemeKeys.LookupResourceKey(this.ResourceKey); + public object? TryFindResource(FrameworkElement referElement) + { + if (referElement == null) return null; + object? result = referElement.TryFindResource(this.ResourceKey); + + if (result == null && this.LookupResourceKey() is ComponentResourceKey resourceKey) + result = referElement.TryFindResource(resourceKey); + + return result; + } + } +} diff --git a/DeedyDesigner/Deedy.Activity/BasalAction.cs b/DeedyDesigner/Deedy.Activity/BasalAction.cs index 5300ef7..518f3eb 100644 --- a/DeedyDesigner/Deedy.Activity/BasalAction.cs +++ b/DeedyDesigner/Deedy.Activity/BasalAction.cs @@ -16,6 +16,22 @@ namespace Deedy.Activity public string DERemark { get; set; } = ""; public string DEIdentify { get; set; } = ""; public int DepthLevel { get; protected internal set; } = 0; + public bool IsLockedElement { get; set; } = false; + protected internal LogInfo _InstantInfo = LogInfo.Empty; + /// + /// 即时消息 + /// + public LogInfo InstantInfo + { + get { return GetField(ref _InstantInfo); } + set + { + if (SetField(ref _InstantInfo, value)) + { + // 这里可以加入属性变更后的处理逻辑 + } + } + } public IElement? ParentElement { get; protected internal set; } public IActionViewer? ActionViewer { get; protected internal set; } diff --git a/DeedyDesigner/Deedy.Activity/Contract/Entities/DragDropData.cs b/DeedyDesigner/Deedy.Activity/Contract/Entities/DragDropData.cs new file mode 100644 index 0000000..f2d6491 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Contract/Entities/DragDropData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + public class DragDropData + { + public DragDropData() { } + public DropPlacement Placement { get; set; } + } +} diff --git a/DeedyDesigner/Deedy.Activity/Contract/Entities/LogInfo.cs b/DeedyDesigner/Deedy.Activity/Contract/Entities/LogInfo.cs index a5a9aa1..b52995a 100644 --- a/DeedyDesigner/Deedy.Activity/Contract/Entities/LogInfo.cs +++ b/DeedyDesigner/Deedy.Activity/Contract/Entities/LogInfo.cs @@ -1,14 +1,24 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Media; using System.Windows.Shapes; namespace Deedy.Activity { public class LogInfo { - public LogInfo() { } + private LogInfo() { } + [AllowNull] + public ImageSource Icon { get; set; } + public readonly static LogInfo Empty = new(); + public override string ToString() + { + //TODO:返回序列化后的消息 + return ""; + } } } diff --git a/DeedyDesigner/Deedy.Activity/Contract/Enums/ExitlinePosition.cs b/DeedyDesigner/Deedy.Activity/Contract/Enums/ExitlinePosition.cs index 9f3fc1c..a1d2c72 100644 --- a/DeedyDesigner/Deedy.Activity/Contract/Enums/ExitlinePosition.cs +++ b/DeedyDesigner/Deedy.Activity/Contract/Enums/ExitlinePosition.cs @@ -9,6 +9,7 @@ namespace Deedy.Activity /// /// 退出线位置(如果需要回归线则放置到相反方向) /// + [Flags] public enum ExitlinePosition : int { /// @@ -24,12 +25,8 @@ namespace Deedy.Activity /// Rightlower = 2, /// - /// 中间竖线:内容节点底部中间直接向下划线退出 - /// - Centerline = 3, - /// /// 下方直线:沿左下角向右下角画完整的直线退出 /// - Underline = 4 + Underline = 3 } } diff --git a/DeedyDesigner/Deedy.Activity/Contract/Interface/IContainerElement.cs b/DeedyDesigner/Deedy.Activity/Contract/Interface/IContainerElement.cs index 756251c..d4b9eaa 100644 --- a/DeedyDesigner/Deedy.Activity/Contract/Interface/IContainerElement.cs +++ b/DeedyDesigner/Deedy.Activity/Contract/Interface/IContainerElement.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; namespace Deedy.Activity { @@ -16,5 +17,64 @@ namespace Deedy.Activity if (index < this.Elements.Count) this.Elements.Insert((int)index, element); if (index >= this.Elements.Count) this.Elements.Add(element); } + /// + /// 如果类型上没有组装规则,则认为不允许组装,否则按照组装规则处理 + /// + /// 要进行组装检查的单元实例 + /// 是否允许组装 + public bool CombineChecking(IElement element, out DragDropEffects effects) + { + DragDropEffects resultEffects = DragDropEffects.None; + List _AllowTypes = []; + List _RejectTypes = []; + this.GetCombineRules(ref _AllowTypes, ref _RejectTypes); + if (element == null) + { + effects = resultEffects; + return false; + } + // 如果没有组装规则则直接返回 + if (_AllowTypes.Count == 0 && _RejectTypes.Count == 0) + { + effects = resultEffects; + return false; + } + + Type uType = element.GetType(); + bool allow = false; + foreach (var aRule in _AllowTypes) + { + if (aRule.BaseType.IsAssignableFrom(uType)) + { + if (!aRule.Excluded.Contains(uType)) + { + allow = true; + break; + } + } + } + if (!allow) + { + effects = resultEffects; + return allow; // 如果没有匹配的放行规则则直接返回 + } + + resultEffects |= DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link; + + foreach (var rRule in _RejectTypes) + { + if (rRule.BaseType.IsAssignableFrom(uType)) + { + if (!rRule.Excluded.Contains(uType)) + { + resultEffects &= DragDropEffects.None; + allow = false; + break; + } + } + } + effects = resultEffects; + return allow; + } } } diff --git a/DeedyDesigner/Deedy.Activity/Contract/Interface/ICriticalZoneManageable.cs b/DeedyDesigner/Deedy.Activity/Contract/Interface/ICriticalZoneManageable.cs new file mode 100644 index 0000000..6ecba62 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Contract/Interface/ICriticalZoneManageable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + public interface ICriticalZoneManageable + { + bool IsEntryZoneHidden { get; set; } + bool IsLeaveZoneHidden { get; set; } + } +} diff --git a/DeedyDesigner/Deedy.Activity/Contract/Interface/IExitlineManageable.cs b/DeedyDesigner/Deedy.Activity/Contract/Interface/IExitlineManageable.cs new file mode 100644 index 0000000..2c43099 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Contract/Interface/IExitlineManageable.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + public interface IExitlineManageable + { + ExitlinePosition ExitlinePosition { get; set; } + } +} diff --git a/DeedyDesigner/Deedy.Activity/Controller/ActivityRepository.cs b/DeedyDesigner/Deedy.Activity/Controller/ActivityRepository.cs new file mode 100644 index 0000000..4c5d254 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Controller/ActivityRepository.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Deedy.Activity +{ + /// + /// 「活动:Activity」仓库 + /// + public class ActivityRepository + { + public ActivityRepository(bool isNeedOriginalActivity = false) + { + // + } + public ActivityRepository(Assembly assembly) + { + // + } + public ActivityRepository Append(Assembly assembly) + { + // + return this; + } + public ActivityRepository Append(string assemblyFilePath) => this.Append(Assembly.LoadFile(assemblyFilePath)); + public ActivityRepository Append(Type type) => this.Append(type.Assembly.CreateInstance(type.FullName ?? "") as IElement); + public ActivityRepository Append([AllowNull] IElement element) + { + // + return this; + } + } +} diff --git a/DeedyDesigner/Deedy.Activity/DeedyHelper.cs b/DeedyDesigner/Deedy.Activity/DeedyHelper.cs deleted file mode 100644 index 617160a..0000000 --- a/DeedyDesigner/Deedy.Activity/DeedyHelper.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Deedy.Activity -{ - public static class DeedyHelper - { - /// - /// 根据名称为一个对象的指定属性赋值 - /// - /// 属性的数据类型 - /// 要操作的目标对象 - /// 属性名 - /// 属性值 - /// 属性约束 - /// 错误的原因 - internal static void SetNamedPropertyValue(this object target, string propertyName, TValue value, - BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.SetProperty) - { - if (target == null || string.IsNullOrEmpty(propertyName)) throw new Exception("目标对象与属性名可能为空,无法对其赋值..."); - Type type = target.GetType(); - PropertyInfo? property = type.GetProperty(propertyName, bindingFlags); - if (property == null) throw new Exception("目标对象上找不到指定名称的可赋值属性..."); - if (value != null && !property.PropertyType.IsInstanceOfType(value)) throw new Exception("要赋予目标对象指定属性的值不匹配属性类型..."); - property.SetValue(target, value); - } - /// - /// 根据名称获取一个对象的指定属性的值 - /// - /// 属性的数据类型 - /// 要操作的目标对象 - /// 属性名 - /// 属性约束 - /// 属性值 - /// 错误的原因 - internal static TValue? GetNamedPropertyValue(this object target, string propertyName, - BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty) - { - if (target == null || string.IsNullOrEmpty(propertyName)) throw new Exception("目标对象与属性名可能为空,无法完成取值..."); - Type type = target.GetType(); - PropertyInfo? property = type.GetProperty(propertyName, bindingFlags); - if (property == null) throw new Exception("目标对象上找不到指定名称的可取值属性..."); - object? value = property.GetValue(target); - if (typeof(TValue).IsInstanceOfType(value)) return (TValue?)value; - throw new Exception("对象上指定属性的当前值不是期望类型的有效实例..."); - } - /// - /// 帮助一个IElement节点构建参数映射表 - /// - /// 需要构建参数映射表的Element节点 - /// 消息输出器 - public static void BuildParamMapping(this IElement element, Output? output = null) - { - // - } - /// - /// 将一个元素插入到当前节点前方「前提:当前节点的父级必须是可变容器节点」 - /// - /// 当前节点 - /// 待插入的节点 - public static void InsertElementToFore(this IElement element, IElement insertion) - { - // - } - /// - /// 将一个元素插入到当前节点后方「前提:当前节点的父级必须是可变容器节点」 - /// - /// 当前节点 - /// 待插入的节点 - public static void InsertElementAtRear(this IElement element, IElement insertion) - { - // - } - /// - /// 将当前节点从父节点中移除 - /// - /// 要移除的元素 - public static void RemoveFromParent(this IElement element) - { - if (element != null && element.ParentElement is IContainerElement container) container.Remove(element); - } - } -} diff --git a/DeedyDesigner/Deedy.Activity/Helper.cs b/DeedyDesigner/Deedy.Activity/Helper.cs new file mode 100644 index 0000000..47d8ff3 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Helper.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows; + +namespace Deedy.Activity +{ + public static partial class Helper + { + /// + /// 根据名称为一个对象的指定属性赋值 + /// + /// 属性的数据类型 + /// 要操作的目标对象 + /// 属性名 + /// 属性值 + /// 属性约束 + /// 错误的原因 + internal static void SetNamedPropertyValue(this object target, string propertyName, TValue value, + BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.SetProperty) + { + if (target == null || string.IsNullOrEmpty(propertyName)) throw new Exception("目标对象与属性名可能为空,无法对其赋值..."); + Type type = target.GetType(); + PropertyInfo? property = type.GetProperty(propertyName, bindingFlags); + if (property == null) throw new Exception("目标对象上找不到指定名称的可赋值属性..."); + if (value != null && !property.PropertyType.IsInstanceOfType(value)) throw new Exception("要赋予目标对象指定属性的值不匹配属性类型..."); + property.SetValue(target, value); + } + /// + /// 根据名称获取一个对象的指定属性的值 + /// + /// 属性的数据类型 + /// 要操作的目标对象 + /// 属性名 + /// 属性约束 + /// 属性值 + /// 错误的原因 + internal static TValue? GetNamedPropertyValue(this object target, string propertyName, + BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetProperty) + { + if (target == null || string.IsNullOrEmpty(propertyName)) throw new Exception("目标对象与属性名可能为空,无法完成取值..."); + Type type = target.GetType(); + PropertyInfo? property = type.GetProperty(propertyName, bindingFlags); + if (property == null) throw new Exception("目标对象上找不到指定名称的可取值属性..."); + object? value = property.GetValue(target); + if (typeof(TValue).IsInstanceOfType(value)) return (TValue?)value; + throw new Exception("对象上指定属性的当前值不是期望类型的有效实例..."); + } + /// + /// 在可视化树中查找指定类型的祖先元素,支持指定层级 + /// + /// 要查找的祖先元素类型 + /// 起始子元素 + /// 要查找的祖先层级(1=父级,2=祖父级等) + /// 找到的祖先元素,若未找到则返回null + public static T? FindAncestor(this DependencyObject @object, int level = 1) where T : DependencyObject + { + if (@object == null || level < 1) return null; + + DependencyObject parent = @object; + int currentLevel = 0; + + while (parent != null && currentLevel < level) + { + parent = VisualTreeHelper.GetParent(parent); + if (parent is T foundParent) + { + // 每次找到一个约定类型的袓辈节点计数需要加1 + currentLevel++; + if (currentLevel >= level) + return foundParent; + } + } + + return null; + } + /// + /// 帮助一个IElement节点构建参数映射表 + /// + /// 需要构建参数映射表的Element节点 + /// 消息输出器 + public static void BuildParamMapping(this IElement element, Output? output = null) + { + // + } + /// + /// 将一个元素插入到当前节点前方「前提:当前节点的父级必须是可变容器节点」 + /// + /// 当前节点 + /// 待插入的节点 + public static void InsertElementToFore(this IElement element, IElement insertion) + { + if (element == null || insertion == null || insertion.ParentElement is ICombinedElement) return; + } + /// + /// 将一个元素插入到当前节点后方「前提:当前节点的父级必须是可变容器节点」 + /// + /// 当前节点 + /// 待插入的节点 + public static void InsertElementAtRear(this IElement element, IElement insertion) + { + if (element == null || insertion == null || insertion.ParentElement is ICombinedElement) return; + } + /// + /// 将当前节点从父节点中移除 + /// + /// 要移除的元素 + public static void RemoveFromParent(this IElement element) + { + if (element != null && element.ParentElement is IContainerElement container) container.Remove(element); + } + private static readonly Dictionary, List)> StaticField_CombineRules = []; + /// + /// 查询可动态组装集合的组合规则 + /// + /// 要查询的元素 + /// 允许规则集合 + /// 禁止规则集合 + public static void GetCombineRules(this IContainerElement element, + ref List allowTypes, + ref List rejectTypes) + { + if (element == null) return; + Type type = element.GetType(); + if (!StaticField_CombineRules.ContainsKey(type)) + { + var _AllowTypes = new List(); + var _RejectTypes = new List(); + + var clearRule = type.GetCustomAttribute(false); + if (clearRule != null) + { + var allowRules = type.GetCustomAttributes(false); + foreach (var rule in allowRules) _AllowTypes.Add(rule); + var rejectRules = type.GetCustomAttributes(false); + foreach (var rule in rejectRules) _RejectTypes.Add(rule); + } + else + { + //沿着继承链查找具备「CombineRule_ClearInheritedAttribute」特性的类型,获取组装属性 + List types = []; + Type? baseType = type.BaseType; + while (baseType != null) + { + types.Add(baseType); + clearRule = baseType.GetCustomAttribute(false); + if (clearRule != null) break; + baseType = baseType.BaseType; + } + foreach (var ruleType in types) + { + var aRules = ruleType.GetCustomAttributes(false); + foreach (var rule in aRules) _AllowTypes.Add(rule); + var rRules = ruleType.GetCustomAttributes(false); + foreach (var rule in rRules) _RejectTypes.Add(rule); + } + } + StaticField_CombineRules.Add(type, (allowTypes, rejectTypes)); + } + + (List allowTypes, List rejectTypes) rules + = StaticField_CombineRules[type]; + allowTypes.AddRange(rules.allowTypes); + rejectTypes.AddRange(rules.rejectTypes); + } + /// + /// 校验一个节点是否处于跳过执行逻辑 + /// + /// 要检查的节点 + /// 是否需要跳过执行过程 + public static bool IsNeedBypassing(this IActionElement element) + { + if (element == null) return false; + var parent = element.ParentElement; + while (parent != null) + { + if (parent is IPassable passable) + return passable.IsBypassing; + else parent = parent.ParentElement; + } + return false; + } + /// + /// 查找指定类型的祖辈元素 + /// + /// 要查找的祖非类型 + /// 查找的起点 + /// 查找的层级,默认1级 + /// 如果找到根元素也未找到则返回「null」 + public static T? FindAncestorElement(this IElement element, int level = 1) where T : IElement + { + if (element == null || level < 1) return default; + + var parent = element.ParentElement; + int currentLevel = 0; + + while (parent != null && currentLevel < level) + { + if (parent is T foundParent) + { + // 每次找到一个约定类型的袓辈节点计数需要加1 + currentLevel++; + if (currentLevel >= level) + return foundParent; + } + else parent = parent.ParentElement; + } + + return default; + } + } +} diff --git a/DeedyDesigner/Deedy.Activity/IActionElement.cs b/DeedyDesigner/Deedy.Activity/IActionElement.cs index 9b9019f..bcc2be1 100644 --- a/DeedyDesigner/Deedy.Activity/IActionElement.cs +++ b/DeedyDesigner/Deedy.Activity/IActionElement.cs @@ -9,5 +9,7 @@ namespace Deedy.Activity public interface IActionElement : IElement { public IActionViewer? ActionViewer { get; } + public bool IsLockedElement { get; set; } + public LogInfo InstantInfo { get; } } } diff --git a/DeedyDesigner/Deedy.Activity/IActionViewer.cs b/DeedyDesigner/Deedy.Activity/IActionViewer.cs index 0fe8f15..d5ea39e 100644 --- a/DeedyDesigner/Deedy.Activity/IActionViewer.cs +++ b/DeedyDesigner/Deedy.Activity/IActionViewer.cs @@ -7,6 +7,7 @@ using System.Security.Policy; using System.Text; using System.Threading.Tasks; using System.Windows; +using System.Windows.Controls; using System.Windows.Media; namespace Deedy.Activity @@ -19,29 +20,34 @@ namespace Deedy.Activity public Visibility ShowContinueHandle { get; } public Visibility ShowExitHandle { get; } public Visibility ShowReturnHandle { get; } - public Visibility ShowCustomHandle { get; } - public Visibility ShowHeader { get; } - public Visibility ShowFooter { get; } + public Visibility ShowCustomizeHandle { get; } + public Visibility ShowEntryZone { get; } + public Visibility ShowLeaveZone { get; } public Visibility ShowInfoHandle { get; } public Visibility ShowDeleteHandle { get; } public Visibility ShowLeftExitline { get; } public Visibility ShowRightExitline { get; } - public uint ElementCount { get; } - public bool IsCanExpand { get; } + public int ElementCount { get; } + public bool IsExpandable { get; } public bool IsExpanded { get; } - public bool IsSelectable { get; } - public bool IsSelected { get; } + public bool IsSelectable { get; } + public bool IsSelected { get; } + public bool IsDraggable { get; } + public bool IsDragging { get; } [AllowNull] public LogInfo InstantInfo { get; } [AllowNull] public LogInfoCollection LogInfos { get; } public ViewerState ViewerState { get; } public WorkMode WorkMode { get; } - public Brush FillBrush { get; } - public Brush StrokeBrush { get; } - public double StrokeThickness { get; } - public Thickness MarginCorrection_Top { get; } - public Thickness MarginCorrection_Bottom { get; } - public Thickness MarginCorrection_TopBottom { get; } + public Brush FillBrush { get; set; } + public Brush StrokeBrush { get; set; } + public double StrokeThickness { get; set; } + public Thickness MarginCorrection_Top { get; } + public Thickness MarginCorrection_Bottom { get; } + public Thickness MarginCorrection_TopBottom { get; } + public ImageSource ElementIcon { get; } + [AllowNull] + public StyleSelector StyleSelector { get; set; } } } diff --git a/DeedyDesigner/Deedy.Activity/Resources/ThemeKeys.cs b/DeedyDesigner/Deedy.Activity/Resources/ThemeKeys.cs new file mode 100644 index 0000000..cee1e77 --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Resources/ThemeKeys.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Deedy.Activity +{ + public static class ThemeKeys + { + public const string KEY_Activity_DefaultIcon = "Activity_DefaultIcon"; + public static ComponentResourceKey? LookupResourceKey(string themeKey) + { + if (typeof(ThemeKeys).GetProperty(themeKey, typeof(ComponentResourceKey)) is PropertyInfo pInfo) + return pInfo.GetValue(null) as ComponentResourceKey; + return null; + } + + public static ComponentResourceKey Activity_DefaultIcon => new ComponentResourceKey(typeof(ThemeKeys), "Activity_DefaultIcon"); + + } +} diff --git a/DeedyDesigner/Deedy.Activity/Resources/ThemeResources.cs b/DeedyDesigner/Deedy.Activity/Resources/ThemeResources.cs new file mode 100644 index 0000000..1b9af5e --- /dev/null +++ b/DeedyDesigner/Deedy.Activity/Resources/ThemeResources.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media; + +namespace Deedy.Activity +{ + public partial class ThemeResources : ResourceDictionary + { + public ImageSource? Activity_DefaultIcon => this[ThemeKeys.Activity_DefaultIcon] as ImageSource; + } +} diff --git a/DeedyDesigner/Deedy.Activity/Themes/Generic.xaml b/DeedyDesigner/Deedy.Activity/Themes/Generic.xaml index db27fec..a9bd0b5 100644 --- a/DeedyDesigner/Deedy.Activity/Themes/Generic.xaml +++ b/DeedyDesigner/Deedy.Activity/Themes/Generic.xaml @@ -8,10 +8,21 @@ - - + + + + + + + + +