CNC 标记右键显示 Mark 菜单

人工标记右键显示 Mark 菜单
统一提供编辑属性、显示关联图像、删除、恢复位置等菜单
继续屏蔽底层 RoiCanvas 的缩放/保存菜单,避免两个菜单同时出现
This commit is contained in:
zhengxuan.zhang
2026-08-12 09:56:53 +08:00
parent df3ecbf9fe
commit af77af4aab
4 changed files with 80 additions and 32 deletions
@@ -758,7 +758,13 @@ namespace XP.ImageProcessing.RoiControl.Controls
ClearOverlayLayer(layer);
if (overlayCanvas == null) return;
overlayCanvas.IsHitTestVisible = false;
// 结果/辅助叠加层默认不参与命中测试;检查标记层例外,保留其自身的命中配置,
// 以便标记图标可以处理右键,而空白区域仍由 Background=null 穿透到底层画布。
if (layer != ViewportOverlayLayer.InspectionMarks)
overlayCanvas.IsHitTestVisible = false;
System.Diagnostics.Debug.WriteLine(
$"[ViewportMouse] AttachOverlay layer={layer}, hitTest={overlayCanvas.IsHitTestVisible}, " +
$"background={overlayCanvas.Background ?? System.Windows.Media.Brushes.Transparent}");
overlayCanvas.SetBinding(Canvas.WidthProperty, new System.Windows.Data.Binding("CanvasWidth") { Source = this });
overlayCanvas.SetBinding(Canvas.HeightProperty, new System.Windows.Data.Binding("CanvasHeight") { Source = this });
if (layer == ViewportOverlayLayer.InspectionMarks)
@@ -2746,6 +2752,9 @@ namespace XP.ImageProcessing.RoiControl.Controls
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
System.Diagnostics.Debug.WriteLine(
$"[ViewportMouse] RoiCanvas.MouseRightButtonDown source={e.OriginalSource?.GetType().Name}, " +
$"handled={e.Handled}, point={e.GetPosition(mainCanvas)}");
// BGA 模式下右键切换气泡/焊球
if (CurrentMeasureMode == Models.MeasureMode.BgaVoid && _bgaCurrent != null)
{
@@ -2760,6 +2769,9 @@ namespace XP.ImageProcessing.RoiControl.Controls
private void Canvas_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
System.Diagnostics.Debug.WriteLine(
$"[ViewportMouse] RoiCanvas.PreviewMouseRightButtonUp source={e.OriginalSource?.GetType().Name}, " +
$"handled={e.Handled}, suppress={SuppressContextMenu}");
// BGA 模式下阻止 ContextMenu 弹出
if (CurrentMeasureMode == Models.MeasureMode.BgaVoid && _bgaCurrent != null)
{
@@ -29,8 +29,9 @@ namespace XplorePlane.Views.Main.Overlays
public InspectionMarkOverlay()
{
// 默认状态:无工具激活 → 不拦截鼠标事件,避免阻挡下层的测量拖拽/图像平移等
IsHitTestVisible = false;
// 背景保持 null,不拦截空白区域的鼠标事件;标记图标自身仍需可命中,
// 这样实时预览区右键标记时可以先由标记层处理,避免落到底层 RoiCanvas 菜单。
IsHitTestVisible = true;
Background = null;
MouseLeftButtonDown += OnMouseLeftButtonDown;
MouseRightButtonDown += OnMouseRightButtonDown;
@@ -87,11 +88,13 @@ namespace XplorePlane.Views.Main.Overlays
private static void OnVisualStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var overlay = (InspectionMarkOverlay)d;
// 仅当标记工具激活时才允许命中测试,否则 Background=Transparent 会拦截
// 下层所有鼠标事件(测量拖拽、图像平移、ROI 编辑等)
bool isInteractive = !overlay.IsReadOnly && overlay.ActiveTool != InspectionMapActiveTool.None;
overlay.IsHitTestVisible = isInteractive;
overlay.Background = isInteractive ? Brushes.Transparent : null;
// 背景为 null 时,空白区域继续穿透到下层;但标记图标必须保持命中,
// 否则实时预览区的右键会直接触发 RoiCanvas 的缩放/保存菜单
bool canHitMarks = !overlay.IsReadOnly && overlay.ShowMarks;
overlay.IsHitTestVisible = canHitMarks;
overlay.Background = canHitMarks && overlay.ActiveTool != InspectionMapActiveTool.None
? Brushes.Transparent
: null;
overlay.RenderMarks();
}
@@ -123,6 +126,9 @@ namespace XplorePlane.Views.Main.Overlays
icon.MouseLeave += (_, _) => icon.Opacity = 1.0;
icon.MouseRightButtonDown += (s, e) =>
{
System.Diagnostics.Debug.WriteLine(
$"[ViewportMouse] Mark.MouseRightButtonDown type={mark.Type}, cncNode={mark.CncNodeId}, " +
$"source={e.OriginalSource?.GetType().Name}, handled={e.Handled}");
e.Handled = true;
MarkContextMenuRequested?.Invoke(this, mark);
};
@@ -213,6 +219,9 @@ namespace XplorePlane.Views.Main.Overlays
{
var hit = Children.OfType<FrameworkElement>()
.FirstOrDefault(c => IsNear(e.GetPosition(this), c));
System.Diagnostics.Debug.WriteLine(
$"[ViewportMouse] MarkOverlay.MouseRightButtonDown hit={hit?.Tag is InspectionMarkRecord}, " +
$"source={e.OriginalSource?.GetType().Name}, handled={e.Handled}, point={e.GetPosition(this)}");
if (hit?.Tag is InspectionMarkRecord mark)
{
MarkContextMenuRequested?.Invoke(this, mark);
@@ -328,6 +328,13 @@ namespace XplorePlane.Views.Main
};
_inspectionMarkOverlay.MarkContextMenuRequested += (_, mark) =>
{
_log.Information("[ViewportMouse] MarkContextMenuRequested markId={MarkId}, type={Type}, " +
"status={Status}, cncNodeId={CncNodeId}, cncRunId={CncRunId}",
mark.MarkId,
mark.Type,
mark.Status,
mark.CncNodeId,
mark.CncRunId);
vm.SelectedMark = mark;
ShowInspectionMarkContextMenu(mark, vm);
};
@@ -345,6 +352,11 @@ namespace XplorePlane.Views.Main
private void ShowInspectionMarkContextMenu(InspectionMarkRecord mark, ViewModels.Inspection.Documentation.InspectionMapViewModel vm)
{
// CNC 标记和人工标记统一使用 Mark 菜单;仅屏蔽底层 RoiCanvas 的默认菜单。
_log.Information("[ViewportMouse] Show Mark context menu markId={MarkId}, cncNodeId={CncNodeId}",
mark.MarkId,
mark.CncNodeId);
var menu = new System.Windows.Controls.ContextMenu();
var properties = new System.Windows.Controls.MenuItem { Header = "编辑属性" };
properties.Click += (_, _) =>
@@ -233,10 +233,25 @@ namespace XplorePlane.Views.Main
RoiCanvas.ContextMenu = menu;
RoiCanvas.ContextMenuOpening += (s, e) =>
{
if (RoiCanvas.SuppressContextMenu)
var originalSource = e.OriginalSource as System.Windows.DependencyObject;
bool isInspectionMarkSource = _inspectionMarkOverlay != null &&
originalSource is System.Windows.Media.Visual visual &&
(ReferenceEquals(visual, _inspectionMarkOverlay) ||
visual.IsDescendantOf(_inspectionMarkOverlay));
_log.Information("[ViewportMouse] RoiCanvas.ContextMenuOpening source={Source}, original={OriginalSource}, " +
"handled={Handled}, suppress={SuppressContextMenu}, markSource={MarkSource}, markHitTest={MarkHitTest}",
s?.GetType().Name,
e.OriginalSource?.GetType().Name,
e.Handled,
RoiCanvas.SuppressContextMenu,
isInspectionMarkSource,
_inspectionMarkOverlay?.IsHitTestVisible);
if (RoiCanvas.SuppressContextMenu || isInspectionMarkSource)
{
RoiCanvas.SuppressContextMenu = false;
e.Handled = true;
_log.Information("[ViewportMouse] RoiCanvas context menu suppressed, reason={Reason}",
isInspectionMarkSource ? "inspection-mark" : "external-request");
}
};