Files
DeedyDesigner/DeedyDesigner/Deedy.Activity/ActionViewer.cs
2025-09-17 11:54:04 +08:00

870 lines
40 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 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)
{
//TODO发送节点选中事件
if (this.ActionElement is IContainerForFunction container)
{
if (container.IsEmbedded) this.IsExpanded = true;
else
{
//TODO发送打开辅助编辑器事件
}
}
}
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>
[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);
}
}
if (newValue.IsLockedElement)
{
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.AdjustExitlinePosition();
}
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.AdjustExitlinePosition();
}
protected virtual void ActionElement_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
//TODO处理托管的IActionElement节点的属性变更
case nameof(IActionElement.InstantInfo):
this.InstantInfo = this.ActionElement.InstantInfo;
break;
case nameof(IContainerWithExitline.ExitlinePosition):
// 自身退出线变更时调整所有子节点退出线位置
(this.ActionElement as IContainerWithExitline)?.AdjustExitlinePosition();
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;
}
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);
}
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)
{
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);
}
}
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
}
}