【问题标题】:A selection-rectangle (drawn by mouse on canvas) does not recognize rectangles, which are inside that selection-rectangle (C# WPF)选择矩形(通过鼠标在画布上绘制)无法识别位于该选择矩形内的矩形(C# WPF)
【发布时间】:2022-01-19 07:28:58
【问题描述】:

我现在真的很绝望。我只是无法更进一步,原则上它不应该那么困难。我尝试在过去 2 周内解决它。 以下任务/问题: 我的 C# WPF 项目中有一个名为“MarkPointsMap”的画布,上面有不同类型的标记点(3 种不同颜色的矩形)。一个 MarkPointsMap 可以在整个 MarkPointsMap 中包含大约 3000-4000 个不同的 MarkPoints(该画布的子项)。 MarkPoints 的位置从一个 .tab 文件中加载,该文件被转换为一个名为“MarkPoints”的列表,并在加载相应的 .tab 文件后作为子项添加到“MarkPointsMap”画布上。

这是 MarkPointsMap 的屏幕截图:

有例如大部分是小矩形(绿色),一些中间矩形(黄色)和两个大矩形(红色)。应使用选择矩形选择多个标记点。在我的项目中,我已经可以绘制选择矩形,但是“if this.selectRect.Contains(MarkPointsMap.Children)”(见下文)部分不起作用。

选择矩形如下所示:

以下方法“drawMarkPoints”,在程序中加载.tab文件后调用,在画布“MarkPointsMap”上绘制标记点:

public void drawMarkPoints()
    {
        MarkPointsMap.Children.Clear();

        foreach (MarkPoint markpoint in this.Marks.markpoints)
        {
            if (markpoint.type.relevant)
            {
                Rectangle markpointArea = new Rectangle();
                markpointArea.Tag = markpoint;
                //!!
                SolidColorBrush mySolidColorBrush = new SolidColorBrush();
                mySolidColorBrush.Color = markpoint.fillColor;
                markpointArea.Fill = mySolidColorBrush;
                markpointArea.StrokeThickness = 0.2;
                markpointArea.Stroke = Brushes.Black;

                markpointArea.Width = markpoint.symbol.Width;
                markpointArea.Height = markpoint.symbol.Height;
                //set the markpoints in canvas 
                Canvas.SetLeft(markpointArea, getCanvasCoordinates(markpoint.center).X - 0.5 * markpoint.symbol.Width); 
                Canvas.SetTop(markpointArea, getCanvasCoordinates(markpoint.center).Y - 0.5 * markpoint.symbol.Height);

                MarkPointsMap.Children.Add(markpointArea);
          
            }
        }
    }

使用三个鼠标事件(MarkPointsMap_MouseDown、MarkPointsMap_MouseMove、MarkPointsMap_MouseUp)在画布“MarkPointsMap”中绘制选择矩形:

public Rect itemRect;
public Rect selectRect;
private point anchorPoint; 
private Rectangle manualDragRect = new Rectangle(); 

private void MarkPointsMap_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ChangedButton == MouseButton.Left)
        {
            isLeftMouseButtonDownOnWindow = true;
            anchorPoint = e.MouseDevice.GetPosition(MarkPointsMap);
            MarkPointsMap.CaptureMouse();
            e.Handled = true;
            manualDragRect = new Rectangle
            {
                Stroke = Brushes.Red,
                StrokeThickness = 2
            };
            MarkPointsMap.Children.Add(manualDragRect); 
        }       
    }

private void MarkPointsMap_MouseMove(object sender, MouseEventArgs e)
    {
        if (!MarkPointsMap.IsMouseCaptured)
            return;

        Point location = e.MouseDevice.GetPosition(MarkPointsMap);
        double minX = Math.Min(location.X, anchorPoint.X);
        double minY = Math.Min(location.Y, anchorPoint.Y);
        double maxX = Math.Max(location.X, anchorPoint.X);
        double maxY = Math.Max(location.Y, anchorPoint.Y);

        Canvas.SetTop(manualDragRect, minY);
        Canvas.SetLeft(manualDragRect, minX);

        double height = maxY - minY;
        double width = maxX - minX;

        manualDragRect.Height = Math.Abs(height);
        manualDragRect.Width = Math.Abs(width);
        Point xy_2 = new Point((Canvas.GetLeft(manualDragRect) + 0.5 * width), (Canvas.GetTop(manualDragRect) + 0.5 * height));
        this.selectRect = new Rect(xy_2.X, xy_2.Y, width, height);
    }


private void MarkPointsMap _MouseUp(object sender, MouseButtonEventArgs e)
    {
        MarkPointsMap.ReleaseMouseCapture();

        foreach (MarkPoint markpoint in this.Marks.markpoints) 
        {
            Rect itemRect = new Rect(markpoint.center.X, markpoint.center.Y, markpoint.symbol.Width, markpoint.symbol.Height);
            if (selectRect.Contains(itemRect))
            {
                MessageBox.Show("Test!"); // it does not reach this code, if I circle several markpoints with the red selection-rectangle called “selectRect”
                
            }

        }
    }

为什么这不起作用?我想这与从矩形(使用 derictive 的 System.Windows.Shapes)到 struct Rect 的转换有关:IFormattable。 未达到的“if (selectRect.Contains(itemRect)”应在透视图中将选择矩形内的所有标记点着色为红色,然后计算中间的点(x-Coordinate,y-Coordinate) -选择矩形的点并将这个中间点添加回原始 .tab 文件。
任何想法或提示,我该如何继续?提前致谢。 最好的问候!

【问题讨论】:

    标签: c# wpf canvas selection rectangles


    【解决方案1】:

    您的计算似乎有误。您正在抵消selectRect。您将它相对于渲染的manualDragRect 居中。这样一来,您测试的区域与您通过呈现的选择范围定义的区域完全不同。

    此外,您正在Canvas 上捕获鼠标,但在某些不同的控件上释放捕获。它也应该在MarkPointsMap 上发布。还要小心将鼠标事件标记为已处理。如果输入处理不是自定义控件的一部分,您通常应该避免使用它。

    您应该考虑使用ItemsControlCanvas 作为面板。然后,您可以将绘图移动到标记并为 MarkPoint 数据定义 DataTemplate

    我建议使用从manualDragRect 形状返回的原始Rect。这意味着您应该删除 selectRect 字段和相关计算:

    private void MarkPointsMap_MouseUp(object sender, MouseButtonEventArgs e)
    {
      MarkPointsMap.ReleaseMouseCapture();
    
      foreach (MarkPoint markpoint in this.Marks.markpoints)
      {
        Rect itemRect = new Rect(markpoint.center.X, markpoint.center.Y, markpoint.symbol.Width, markpoint.symbol.Height);
    
        Rect selectionBounds = manualDragRect.RenderedGeometry.Bounds;
        selectionBounds.Offset(Canvas.GetLeft(manualDragRect), Canvas.GetTop(manualDragRect));
        if (selectionBounds.Contains(itemRect))
        {
          MessageBox.Show("Test!");
        }
    
        // TODO::Calculate center of selectionBounds
        Point selectionBoundsCenter = ...;
      }
    }
    

    【讨论】:

    • 感谢您的快速回复和输入。在实际项目中 ReleaseMouseCapture();应用于正确的控制。我忘记将画布的真实名称重命名为stackoverflow的编辑名称。对于这个 stackoverflow 帖子,我重命名了整个变量和控件名称,以便真正的项目仍然是匿名的。我现在在原始帖子中更改了它。我试过你的代码,但我仍然有选择矩形的奇怪行为。
    • 我真的很想知道你在哪里以及为什么挣扎。这真的是一个简单的问题。我已经更新了我的答案,为您提供了一个小而简单但完整的工作示例。它还向您展示了如何使用 ItemsControl 作为 Canvas 主机和 DataTemplates 将您的计算/数据与渲染分开。这对您来说应该是一个很好的起点。
    • 问题是缩放问题。 MarkPointsCanvas 的宽度与纸张(导入的 .tab 文件)的宽度相同,并且在其上绘制了 marekpoints。通过正确的缩放,它现在可以工作了。还有你的代码。
    • 很好。那么我可以删除示例 UserControl 吗?
    • 您发布的代码的问题是它没有显示任何缩放。问题中也没有提到。
    猜你喜欢
    • 2012-08-16
    • 2021-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    相关资源
    最近更新 更多