using OpenCvSharp.ML; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using TeamAAS.FlowEngine; using TeamAAS.FlowEditor.Models; using TeamAAS.FlowEditor.Plugins; using Plugins.Standard.Models; using TeamAAS.FlowEditor; using TeamAAS; namespace Plugins.Standard.Views { /// /// 组合模块编辑器视图(UserControl)- 承载在 PluginViewDialog 中。 /// 通过 DataContext 接收 GroupPluginModel,自动初始化子流程编辑器。 /// 实现 IPluginRunFeedback:窗体右下角"执行"按钮执行期间同步内嵌画布的运行态, /// 与画布内"▶ 运行"按钮的反馈保持一致(节点亮灯、锁定编辑、按钮切换)。 /// 实现 IPluginViewTip:把提示写到承载窗体底部提示栏; /// 视图内所有 Tag 为非空字符串的按钮,鼠标悬停时自动在窗体底部显示该提示。 /// public partial class GroupEditorView : UserControl, IPluginViewSave, IPluginRunFeedback, IPluginViewTip { private FlowEditorViewModel _vm; public GroupEditorView() { InitializeComponent(); Loaded += OnLoaded; Unloaded += OnUnloaded; } private void OnUnloaded(object sender, RoutedEventArgs e) { PluginLoader.Instance.SetGroupPluginModel = null; PluginLoader.Instance.ParentGroupModel = null; } private void OnLoaded(object sender, RoutedEventArgs e) { if (DataContext is GroupPluginModel model) { model.EnsureSubGraph(); TxtTitle.Text = model.ToolName ?? "组合模块"; _vm = new FlowEditorViewModel(model.SubGraph, isSubFlowEditor: true); SubFlowEditor.DataContext = _vm; _vm.GraphDataChanged += _vm_PropertyChanged; // 悬停提示:视图内所有 Tag 为非空字符串的按钮(含子流程编辑器工具条), // 鼠标瞄准时把提示文本显示到基窗体底部 Tip 栏 HookHoverHints(this); } } private void _vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (DataContext is GroupPluginModel model) { FlowGraph flowGraph = sender as FlowGraph; // 当子流程图发生变化时,更新模型的 SubGraph model.SubGraph = flowGraph; } } /// /// 窗口关闭前保存更改回模型 /// public void SaveChanges() { if (DataContext is GroupPluginModel model) { if (_vm != null) model.SubGraph = _vm.Graph; } } /// /// 窗体"执行"开始:内嵌子流程编辑器进入运行态(UI 线程同步,避免跨线程访问控件) /// public void BeginRun() { if (_vm == null) return; System.Windows.Application.Current?.Dispatcher.Invoke(() => { _vm.IsRunning = true; }); } /// /// 窗体"执行"结束(含停止/异常):恢复非运行态 /// public void EndRun() { if (_vm == null) return; System.Windows.Application.Current?.Dispatcher.Invoke(() => { _vm.IsRunning = false; }); } #region IPluginViewTip 底部提示栏 private readonly HashSet _hoverHooked = new HashSet(); /// 承载本视图的基窗体(PluginViewDialog),未承载时为 null private TeamAAS.Dialogs.Dialogs.PluginViewDialog HostDialog => System.Windows.Window.GetWindow(this) as TeamAAS.Dialogs.Dialogs.PluginViewDialog; /// 持久提示(执行结果 CT 等)写入基窗体底部提示栏 public void ShowTip(string message) { HostDialog?.ShowTip(message); } /// 鼠标悬停临时提示写入基窗体底部提示栏;null = 结束悬停 public void ShowHoverHint(string message) { HostDialog?.ShowHoverHint(message); } /// 悬停进入:把 Tag 中的提示文本写到窗体底部提示栏 private void HoverEl_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e) { if ((sender as System.Windows.FrameworkElement)?.Tag is string tip && !string.IsNullOrWhiteSpace(tip)) ShowHoverHint(tip); } /// 悬停离开:回落到最近一次持久提示(如执行完成的 CT 信息) private void HoverEl_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e) { ShowHoverHint(null); } /// /// 扫描视觉树,给所有 Tag 为非空字符串的按钮挂上悬停提示。 /// 悬停在控件上时提示显示在承载窗体底部(与执行按钮同排的 Tip 栏)。 /// private void HookHoverHints(System.Windows.DependencyObject root) { if (root == null) return; var count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(root); for (int i = 0; i < count; i++) { var child = System.Windows.Media.VisualTreeHelper.GetChild(root, i); if (child is System.Windows.Controls.Primitives.ButtonBase btn && !_hoverHooked.Contains(btn) && btn.Tag is string tip && !string.IsNullOrWhiteSpace(tip)) { btn.MouseEnter += HoverEl_MouseEnter; btn.MouseLeave += HoverEl_MouseLeave; _hoverHooked.Add(btn); } HookHoverHints(child); } } #endregion private void BtnProperties_Click(object sender, RoutedEventArgs e) { if (DataContext is GroupPluginModel model) { PluginLoader.Instance.SetGroupPluginModel = model.SubGraph; PluginLoader.Instance.ParentGroupModel = model; if (DialogHelper.EditProperties(model, $"组合模块属性 - {model.NodeName}")) { TxtTitle.Text = model.ToolName ?? "组合模块"; DialogHelper.Info($"已更新组合模块属性: {model.ToolName}"); } PluginLoader.Instance.SetGroupPluginModel = null; } } private void UserControl_ContextMenuClosing(object sender, ContextMenuEventArgs e) { } private void UserControl_ToolTipClosing(object sender, ToolTipEventArgs e) { } } }