From 1cc4b5e4d0b75ed7a57489bebb2ee76797dfc908 Mon Sep 17 00:00:00 2001 From: "zhengxuan.zhang" Date: Sun, 15 Mar 2026 00:47:51 +0800 Subject: [PATCH] =?UTF-8?q?#0024=20=E4=BF=AE=E5=A4=8D=E6=B5=AE=E5=8A=A8?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=AE=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PipelineEditorViewModel.cs | 10 ++ .../OperatorToolboxView.xaml.cs | 70 +++++++++---- .../ImageProcessing/PipelineEditorView.xaml | 97 +++++++------------ .../PipelineEditorView.xaml.cs | 46 +++++++-- XplorePlane/readme.txt | 4 + 5 files changed, 133 insertions(+), 94 deletions(-) diff --git a/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs b/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs index ecc4b96..370c9f6 100644 --- a/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs +++ b/XplorePlane/ViewModels/ImageProcessing/PipelineEditorViewModel.cs @@ -141,22 +141,30 @@ namespace XplorePlane.ViewModels private void AddOperator(string operatorKey) { + Serilog.Log.Debug("AddOperator 被调用,operatorKey={OperatorKey}", operatorKey); + if (string.IsNullOrWhiteSpace(operatorKey)) { StatusMessage = "算子键不能为空"; + Serilog.Log.Warning("AddOperator 失败:operatorKey 为空"); return; } var available = _imageProcessingService.GetAvailableProcessors(); + Serilog.Log.Debug("可用算子数量:{Count},包含 {Key}:{Contains}", + available.Count(), operatorKey, available.Contains(operatorKey)); + if (!available.Contains(operatorKey)) { StatusMessage = $"算子 '{operatorKey}' 未注册"; + Serilog.Log.Warning("AddOperator 失败:算子 {Key} 未注册", operatorKey); return; } if (PipelineNodes.Count >= MaxPipelineLength) { StatusMessage = $"流水线节点数已达上限({MaxPipelineLength})"; + Serilog.Log.Warning("AddOperator 失败:节点数已达上限 {Max}", MaxPipelineLength); return; } @@ -167,6 +175,8 @@ namespace XplorePlane.ViewModels }; LoadNodeParameters(node); PipelineNodes.Add(node); + Serilog.Log.Information("节点已添加到 PipelineNodes:{Key} ({DisplayName}),当前节点数={Count}", + operatorKey, displayName, PipelineNodes.Count); StatusMessage = $"已添加算子:{displayName}"; TriggerDebouncedExecution(); } diff --git a/XplorePlane/Views/ImageProcessing/OperatorToolboxView.xaml.cs b/XplorePlane/Views/ImageProcessing/OperatorToolboxView.xaml.cs index eea75e8..d6c3ef5 100644 --- a/XplorePlane/Views/ImageProcessing/OperatorToolboxView.xaml.cs +++ b/XplorePlane/Views/ImageProcessing/OperatorToolboxView.xaml.cs @@ -1,14 +1,18 @@ using System.Windows; using System.Windows.Controls; +using System.Windows.Input; using Prism.Ioc; -using Telerik.Windows.DragDrop; +using Serilog; using XplorePlane.ViewModels; namespace XplorePlane.Views { public partial class OperatorToolboxView : UserControl { - private const string DragFormat = "OperatorDescriptor"; + public const string DragFormat = "PipelineOperatorKey"; + + private Point _dragStartPoint; + private bool _isDragging; public OperatorToolboxView() { @@ -21,29 +25,55 @@ namespace XplorePlane.Views if (DataContext == null) DataContext = ContainerLocator.Container.Resolve(); - // 启用拖拽源 + 注册拖拽初始化事件 - DragDropManager.SetAllowDrag(ToolboxListBox, true); - DragDropManager.AddDragInitializeHandler(ToolboxListBox, OnDragInitialize, true); + ToolboxListBox.PreviewMouseLeftButtonDown += OnPreviewMouseDown; + ToolboxListBox.PreviewMouseMove += OnPreviewMouseMove; + Log.Debug("OperatorToolboxView 原生拖拽源已注册"); } - private void OnDragInitialize(object sender, DragInitializeEventArgs e) + private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e) { - if (ToolboxListBox.SelectedItem is OperatorDescriptor descriptor) + _dragStartPoint = e.GetPosition(null); + _isDragging = false; + } + + private void OnPreviewMouseMove(object sender, MouseEventArgs e) + { + if (e.LeftButton != MouseButtonState.Pressed) return; + + var pos = e.GetPosition(null); + var diff = pos - _dragStartPoint; + + if (!_isDragging + && (System.Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance + || System.Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance)) { - e.AllowedEffects = System.Windows.DragDropEffects.Copy; - DragDropPayloadManager.SetData(e.Data, DragFormat, descriptor); - e.DragVisual = new System.Windows.Controls.TextBlock + _isDragging = true; + + // 从鼠标位置 HitTest 找到 OperatorDescriptor + var hitResult = System.Windows.Media.VisualTreeHelper.HitTest( + ToolboxListBox, e.GetPosition(ToolboxListBox)); + + OperatorDescriptor? descriptor = null; + var node = hitResult?.VisualHit as DependencyObject; + while (node != null) { - Text = descriptor.DisplayName, - Padding = new Thickness(6, 3, 6, 3), - Background = System.Windows.Media.Brushes.LightBlue, - FontFamily = new System.Windows.Media.FontFamily("Microsoft YaHei UI"), - FontSize = 11 - }; - } - else - { - e.Cancel = true; + if (node is FrameworkElement fe && fe.DataContext is OperatorDescriptor d) + { + descriptor = d; + break; + } + node = System.Windows.Media.VisualTreeHelper.GetParent(node); + } + + if (descriptor == null) + { + Log.Warning("拖拽初始化失败:HitTest 未命中算子项"); + return; + } + + Log.Information("开始拖拽算子:{OperatorKey} ({DisplayName})", descriptor.Key, descriptor.DisplayName); + var data = new DataObject(DragFormat, descriptor.Key); + DragDrop.DoDragDrop(ToolboxListBox, data, DragDropEffects.Copy); } } } diff --git a/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml b/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml index bf67c82..17dfad5 100644 --- a/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml +++ b/XplorePlane/Views/ImageProcessing/PipelineEditorView.xaml @@ -17,7 +17,7 @@ Microsoft YaHei UI - - + - - + + - + - - + + (); - // 启用拖拽目标 + 注册 Drop 事件 PipelineListBox.AllowDrop = true; - DragDropManager.AddDropHandler(PipelineListBox, OnOperatorDropped, true); + PipelineListBox.Drop += OnOperatorDropped; + PipelineListBox.DragOver += OnDragOver; + Log.Debug("PipelineEditorView 原生 Drop 目标已注册"); } - private void OnOperatorDropped(object sender, Telerik.Windows.DragDrop.DragEventArgs e) + private void OnDragOver(object sender, DragEventArgs e) { - if (DataContext is not PipelineEditorViewModel vm) return; + if (e.Data.GetDataPresent(OperatorToolboxView.DragFormat)) + e.Effects = DragDropEffects.Copy; + else + e.Effects = DragDropEffects.None; + e.Handled = true; + } - var descriptor = DragDropPayloadManager.GetDataFromObject(e.Data, DragFormat) as OperatorDescriptor; - if (descriptor == null) return; + private void OnOperatorDropped(object sender, DragEventArgs e) + { + if (DataContext is not PipelineEditorViewModel vm) + { + Log.Warning("Drop 事件触发但 DataContext 不是 PipelineEditorViewModel"); + return; + } - vm.AddOperatorCommand.Execute(descriptor.Key); + if (!e.Data.GetDataPresent(OperatorToolboxView.DragFormat)) + { + Log.Warning("Drop 事件触发但数据中无 {Format}", OperatorToolboxView.DragFormat); + return; + } + + var operatorKey = e.Data.GetData(OperatorToolboxView.DragFormat) as string; + if (string.IsNullOrEmpty(operatorKey)) + { + Log.Warning("Drop 事件触发但 OperatorKey 为空"); + return; + } + + Log.Information("算子已放入流水线:{OperatorKey},VM HashCode={Hash},当前节点数(执行前)={Count}", + operatorKey, vm.GetHashCode(), vm.PipelineNodes.Count); + vm.AddOperatorCommand.Execute(operatorKey); + Log.Information("AddOperator 执行后节点数={Count},PipelineListBox.Items.Count={ItemsCount}", + vm.PipelineNodes.Count, PipelineListBox.Items.Count); e.Handled = true; } } diff --git a/XplorePlane/readme.txt b/XplorePlane/readme.txt index 6eee903..d594a0f 100644 --- a/XplorePlane/readme.txt +++ b/XplorePlane/readme.txt @@ -16,4 +16,8 @@ 2、硬件层射线源的集成 √ 3、图像层集成,包括复刻一个示例界面,优化界面布局及算子中文 √ 4、浮动图像处理工具箱调研 √ +5、修复图像工具箱拖拽事件,流水线列表没有生成对应的控件 + + + 5、各窗体间数据流的传递,全局数据结构的设计 \ No newline at end of file