Files
DeedyDesigner/DeedyDesigner/Deedy.Activity/ActionViewer.cs

1024 lines
47 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.Collections.Generic;
using System.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;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Deedy.Activity
{
/// <summary>
/// 用于为Action提供显示视图
/// </summary>
[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 static double IndentRuler { get; set; } = 30;
public ExpandoMapping ExpandoMapping { get; set; } = new ExpandoMapping();
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);
this.LogInfos = new();
}
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;
/// <summary>
/// 发送属性变更通知
/// </summary>
/// <param name="propertyName">发生变更的属性</param>
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
/// <summary>
/// 读取一个字段的值
/// </summary>
/// <typeparam name="T">值的类型,可以通过参数进行自动判定</typeparam>
/// <param name="field">字段的引用【注意:此参数通过引用传递】</param>
/// <param name="propertyName">属性名称;如果在属性的读取访问器中调用可以自动注入</param>
/// <returns>字段中的值</returns>
protected virtual T GetField<T>(ref T field, [CallerMemberName] string? propertyName = null)
{
//TODO这里处理内部属性获取逻辑包括运行时参数映射逻辑
return field;
}
/// <summary>
/// 检查新值是否与原值相等,如果不相等便赋值并发出通知
/// </summary>
/// <typeparam name="T">值的类型,可以通过参数进行自动判定</typeparam>
/// <param name="field">字段的引用【注意:此参数通过引用传递】</param>
/// <param name="value">字段的新值</param>
/// <param name="propertyName">要进行变更通知的属性名称;如果在属性的设置访问器中调用可以自动注入</param>
/// <returns>值是否有变更</returns>
protected virtual bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
//TODO这里处理内部属性变更逻辑包括运行时参数映射逻辑
field = value;
OnPropertyChanged(propertyName);
return true;
}
[AllowNull]
public Runtime Runtime { get; protected internal set; }
/// <summary>
/// 是否显示Break控制手柄
/// </summary>
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;
/// <summary>
/// 是否显示重手柄
/// </summary>
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;
/// <summary>
/// 是否显示退出手柄
/// </summary>
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;
/// <summary>
/// 是否显示返回手柄
/// </summary>
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;
/// <summary>
/// 是否显示自定义手柄
/// </summary>
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;
/// <summary>
/// 是否显示进入区
/// </summary>
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;
/// <summary>
/// 是否显示退出区
/// </summary>
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;
/// <summary>
/// 是否显示消息回显
/// </summary>
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;
/// <summary>
/// 是否显示删除图标
/// </summary>
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;
/// <summary>
/// 显示左侧退出线
/// </summary>
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;
/// <summary>
/// 显示右侧退出线
/// </summary>
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;
/// <summary>
/// 即时消息
/// </summary>
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;
/// <summary>
/// 处理「ActionViewer.InstantInfo」属性变更
/// </summary>
protected virtual void InstantInfo_PropertyChangedCallback(DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is LogInfo logInfo)
{
this.ToolTip = logInfo.ToString();
//TODO更新消息显示图标
this.LogInfos.Add(logInfo);
}
}
/// <summary>
/// 信息列表
/// </summary>
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;
/// <summary>
/// 子元素数量
/// </summary>
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;
/// <summary>
/// 是否可被选中
/// </summary>
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;
/// <summary>
/// 是否选中
/// </summary>
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,
(d, e) => (d as ActionViewer)?.IsSelected_PropertyChangedCallback(e)));
public static readonly DependencyProperty IsSelectedProperty = IsSelectedPropertyKey.DependencyProperty;
/// <summary>
/// 处理「ActionViewer.IsSelected」属性变更
/// </summary>
protected virtual void IsSelected_PropertyChangedCallback(DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
RoutedEventArgs args = new RoutedEventArgs(SelectedEvent, this.ActionElement);
this.RaiseEvent_Selected(args);
if (this.ActionElement is IContainerForFunction container)
{
if (container.IsEmbedded) this.IsExpanded = true;
else
{
RequestOpenDesignerEventArgs reqArgs = new RequestOpenDesignerEventArgs(RequestOpenDesignerEvent, this.ActionElement);
this.RaiseEvent_RequestOpenDesigner(reqArgs);
}
}
}
this.RefreshViewerState();
}
/// <summary>
/// 是否可被展开
/// </summary>
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;
/// <summary>
/// 是否展开
/// </summary>
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;
/// <summary>
/// 是否可被拖动
/// </summary>
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;
/// <summary>
/// 是否正在拖动
/// </summary>
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;
/// <summary>
/// 视图状态
/// </summary>
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;
/// <summary>
/// 处理「ActionViewer.ViewerState」属性变更
/// </summary>
protected virtual void ViewerState_PropertyChangedCallback(DependencyPropertyChangedEventArgs e)
{
this.StyleSelector?.SelectStyle(this.ActionElement, this);
}
/// <summary>
/// 工作模式:非设计模式下不允许拖放操作;编辑、运行、回显三种模式不可相互切换,但可以与等待和预览状态切换。
/// </summary>
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;
/// <summary>
/// 填充画刷
/// </summary>
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));
/// <summary>
/// 画线画刷
/// </summary>
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));
/// <summary>
/// 画线宽度
/// </summary>
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)));
/// <summary>
/// 处理「ActionViewer.StrokeThickness」属性变更
/// </summary>
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;
}
/// <summary>
/// 被托管动作元素的图标
/// </summary>
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;
/// <summary>
/// 视图样式选择器
/// </summary>
[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));
/// <summary>
/// 上边距修正
/// </summary>
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;
/// <summary>
/// 下边距修正
/// </summary>
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;
/// <summary>
/// 上下边距修正
/// </summary>
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;
/// <summary>
/// 缩进边距修正
/// </summary>
public Thickness MarginCorrection_Indentation
{
get { return (Thickness)GetValue(MarginCorrection_IndentationProperty); }
protected internal set { SetValue(MarginCorrection_IndentationPropertyKey, value); }
}
public static readonly DependencyPropertyKey MarginCorrection_IndentationPropertyKey =
DependencyProperty.RegisterReadOnly("MarginCorrection_Indentation", typeof(Thickness), typeof(ActionViewer), new PropertyMetadata(new Thickness()));
public static readonly DependencyProperty MarginCorrection_IndentationProperty = MarginCorrection_IndentationPropertyKey.DependencyProperty;
/// <summary>
/// 动作节点
/// </summary>
[AllowNull, DefaultValue(null)]
public IActionElement ActionElement
{
get { return (IActionElement)GetValue(ActionElementProperty); }
set { SetValue(ActionElementProperty, value); }
}
public static readonly DependencyProperty ActionElementProperty =
DependencyProperty.Register("ActionElement", typeof(IActionElement), typeof(ActionViewer), new PropertyMetadata(null,
(d, e) => (d as ActionViewer)?.ActionElement_PropertyChangedCallback(e)));
/// <summary>
/// 处理「ActionElementViewer.ActionElement」属性变更
/// </summary>
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<IconKeyAttribute>();
if (iconKey != null)
{
ImageSource? icon = iconKey.TryFindResource(this) as ImageSource;
if (icon != null) this.ElementIcon = icon;
else
{
iconKey = this.GetType().GetCustomAttribute<IconKeyAttribute>();
if (iconKey != null) icon = iconKey.TryFindResource(this) as ImageSource;
if (icon != null) this.ElementIcon = icon;
else this.ClearValue(ElementIconPropertyKey);
}
}
this.MarginCorrection_Indentation = new Thickness(newValue.DepthLevel * ActionViewer.IndentRuler, 0, 0, 0);
if (newValue.IsLocked)
{
this.IsDraggable = false;
// 功能容器类型的锁定元素允许被选中
this.IsSelectable = newValue is IContainerForFunction;
}
else
{
this.IsDraggable = true;
this.IsSelectable = true;
}
if (newValue is ICombinedElement newCombined)
{
this.IsExpandable = true;
this.ElementCount = newCombined.Elements.Count;
newCombined.Elements.CollectionChanged += Elements_CollectionChanged;
}
else this.IsExpandable = false;
if (newValue is ICriticalZoneManageable criticalZone)
{
if (criticalZone.IsLeaveZoneHidden) this.ShowLeaveZone = Visibility.Collapsed;
if (criticalZone.IsEntryZoneHidden) this.ShowEntryZone = Visibility.Collapsed;
}
if (newValue is IContainerWithExitline withExitline)
{
if (withExitline.ExitlinePosition.HasFlag(ExitlinePosition.LeftLower))
this.ShowLeftExitline = Visibility.Visible;
if (withExitline.ExitlinePosition.HasFlag(ExitlinePosition.Rightlower))
this.ShowRightExitline = Visibility.Visible;
// 新元素被托管渲染后调整子元素退出线位置
withExitline.Help_ExitlinePositionAdjust();
}
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根据节点的特征与当前工作状态来判定如何处理当前视图的属性
}
}
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;
}
// 节点集合变更时调整退出线位置
if (this.ActionElement is IContainerWithExitline container) container.Help_ExitlinePositionAdjust();
}
protected virtual void ActionElement_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
//TODO处理托管的IActionElement节点的属性变更
case nameof(IElement.DepthLevel):
this.MarginCorrection_Indentation = new Thickness(ActionViewer.IndentRuler * this.ActionElement.DepthLevel, 0, 0, 0);
break;
case nameof(IActionElement.InstantInfo):
this.InstantInfo = this.ActionElement.InstantInfo;
break;
case nameof(IContainerWithExitline.ExitlinePosition):
// 自身退出线变更时调整所有子节点退出线位置
(this.ActionElement as IContainerWithExitline)?.Help_ExitlinePositionAdjust();
break;
default: break;
}
}
public void ReadyToWorking(IElement? element = null, Output? output = null)
{
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)
{
this.ReadyToWorking();
this.WorkMode = WorkMode.Editing;
}
public void ReadyToRunning(Runtime runtime)
{
this.ReadyToWorking();
this.WorkMode = WorkMode.Running;
}
/// <summary>
/// 刷新视图样式
/// </summary>
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;
}
}
}
/// <summary>
/// 检查事件源是否需要自身处理
/// </summary>
/// <param name="eventSource">引发事件的源</param>
/// <returns>只有事件源是自身或事件源的第一个SmartView类型的祖辈是自身时才需要处理</returns>
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<ActionViewer>()) result = true;
return result;
}
#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);
}
protected internal bool _CanDropInParent = false;
protected internal bool _CanDropChild = false;
protected internal 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)
{
if (this.IsSelectable)
{
CancelRoutedEventArgs args = new CancelRoutedEventArgs(PreviewSelectedEvent, this.ActionElement);
this.RaiseEvent_PreviewSelected(args);
this.IsSelected = !args.Cancel;
}
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.IsLocked) 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);
}
}
protected internal readonly object _DragLock = new();
protected internal 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
#region
/// <summary>
/// 节点被选中
/// </summary>
/// <remarks>
/// 当视图节点被选中时发生
/// </remarks>
public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble,
typeof(EventHandler<RoutedEventArgs>), typeof(ActionViewer));
/// <summary>
/// 事件「节点被选中」封装
/// </summary>
public event EventHandler<RoutedEventArgs> Selected
{
add { AddHandler(SelectedEvent, value); }
remove { RemoveHandler(SelectedEvent, value); }
}
/// <summary>
/// 事件「节点被选中」触发
/// </summary>
/// <param name="args">事件参数</param>
protected virtual void RaiseEvent_Selected(RoutedEventArgs args)
{
// 事件触发前可以进行一定的处理逻辑
RaiseEvent(args);
}
/// <summary>
/// 节点将要被选中
/// </summary>
/// <remarks>
/// 当节点要被选中前发生,此事件可以被取消
/// </remarks>
public static readonly RoutedEvent PreviewSelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Tunnel,
typeof(EventHandler<CancelRoutedEventArgs>), typeof(ActionViewer));
/// <summary>
/// 事件「节点将要被选中」封装
/// </summary>
public event EventHandler<CancelRoutedEventArgs> PreviewSelected
{
add { AddHandler(SelectedEvent, value); }
remove { RemoveHandler(SelectedEvent, value); }
}
/// <summary>
/// 事件「节点将要被选中」触发
/// </summary>
/// <param name="args">事件参数</param>
protected virtual void RaiseEvent_PreviewSelected(CancelRoutedEventArgs args)
{
// 事件触发前可以进行一定的处理逻辑
RaiseEvent(args);
}
/// <summary>
/// 请求打开独立的设计器
/// </summary>
/// <remarks>
/// 当一个逻辑容器节点被选中,且要求系统打开独立设计器时发送此事件
/// </remarks>
public static readonly RoutedEvent RequestOpenDesignerEvent = EventManager.RegisterRoutedEvent("RequestOpenDesigner", RoutingStrategy.Bubble,
typeof(EventHandler<RequestOpenDesignerEventArgs>), typeof(ActionViewer));
/// <summary>
/// 事件「请求打开独立的设计器」封装
/// </summary>
public event EventHandler<RequestOpenDesignerEventArgs> RequestOpenDesigner
{
add { AddHandler(RequestOpenDesignerEvent, value); }
remove { RemoveHandler(RequestOpenDesignerEvent, value); }
}
/// <summary>
/// 事件「请求打开独立的设计器」触发
/// </summary>
/// <param name="args">事件参数</param>
protected virtual void RaiseEvent_RequestOpenDesigner(RequestOpenDesignerEventArgs args)
{
// 事件触发前可以进行一定的处理逻辑
RaiseEvent(args);
}
/// <summary>
/// 准备拖动
/// </summary>
/// <remarks>
/// 在对象被拖动之前发生,可以被取消
/// </remarks>
public static readonly RoutedEvent PreviewActionDragEvent = EventManager.RegisterRoutedEvent("ActionDrag", RoutingStrategy.Tunnel,
typeof(EventHandler<CancelRoutedEventArgs>), typeof(ActionViewer));
/// <summary>
/// 事件「准备拖动」封装
/// </summary>
public event EventHandler<CancelRoutedEventArgs> PreviewActionDrag
{
add { AddHandler(PreviewActionDragEvent, value); }
remove { RemoveHandler(PreviewActionDragEvent, value); }
}
/// <summary>
/// 事件「准备拖动」触发
/// </summary>
/// <param name="args">事件参数</param>
protected virtual void RaiseEvent_PreviewActionDrag(CancelRoutedEventArgs args)
{
// 事件触发前可以进行一定的处理逻辑
RaiseEvent(args);
}
/// <summary>
/// 准备放置
/// </summary>
/// <remarks>
/// 在对象被放置之前发生,可以被取消
/// </remarks>
public static readonly RoutedEvent PreviewActionDropEvent = EventManager.RegisterRoutedEvent("ActionDrop", RoutingStrategy.Tunnel,
typeof(EventHandler<CancelRoutedEventArgs>), typeof(ActionViewer));
/// <summary>
/// 事件「准备放置」封装
/// </summary>
public event EventHandler<CancelRoutedEventArgs> PreviewActionDrop
{
add { AddHandler(PreviewActionDropEvent, value); }
remove { RemoveHandler(PreviewActionDropEvent, value); }
}
/// <summary>
/// 事件「准备放置」触发
/// </summary>
/// <param name="args">事件参数</param>
protected virtual void RaiseEvent_PreviewActionDrop(CancelRoutedEventArgs args)
{
// 事件触发前可以进行一定的处理逻辑
RaiseEvent(args);
}
#endregion
}
}