selection-rectangle(用鼠标在 canvas 上绘制)无法识别 selection-rectangle 内的矩形 (C# WPF)
A selection-rectangle (drawn by mouse on canvas) does not recognize rectangles, which are inside that selection-rectangle (C# WPF)
我现在真的很绝望。我只是不能再进一步了,原则上它不应该那么困难。我在过去两周尝试解决它。
以下task/problem:
我的 C# WPF 项目中有一个名为“MarkPointsMap”的 canvas,上面有不同类型的标记点(3 种不同颜色的矩形)。一个 MarkPointsMap 可以包含大约 3000-4000 个不同的 MarkPoints(Children of that canvas)遍布整个 MarkPointsMap。
该 MarkPoints 的位置是从 .tab-file 加载的,它被转换成一个名为“MarkPoints”的列表,并在加载相应的 .tab-file.
这是 MarkPointsMap 的屏幕截图:
有例如大多数是小矩形(绿色的),一些中间的矩形(黄色的)和两个大矩形(红色的)。应使用 selection-rectangle 选择多个标记点。在我的项目中,我已经可以绘制选择矩形,但是“if this.selectRect.Contains(MarkPointsMap.Children)”(见下文)部分不起作用。
selection-rectangle 看起来如下:
程序中加载.tab文件后调用的drawMarkPoints方法在canvas“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);
}
}
}
selection-rectangle是在canvas“MarkPointsMap”中绘制的,三个Mouse-Events(MarkPointsMap_MouseDown、MarkPointsMap_MouseMove、MarkPointsMap_MouseUp) :
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”
}
}
}
为什么这行不通?我想这与从矩形(System.Windows.Shapes 使用描述符)到结构 Rect 的转换有关:IFormattable。
未达到的“if (selectRect.Contains(itemRect)”应该在透视中将selection-rectangle内的所有标记点着色为红色,然后计算点(x-Coordinate, y-Coordinate) 的 selection-rectangle 的 middle-point 并将这个中间点添加回原来的 .tab-file.
任何想法或提示,我该如何继续?提前致谢。
此致!
看来你的计算有误。您正在抵消 selectRect
。您将它相对于呈现的 manualDragRect
居中。这样,您测试的区域与您通过渲染选择边界定义的区域完全不同。
此外,您在 Canvas
上捕获鼠标,但在某些不同的控件上释放捕获。它也应该在 MarkPointsMap
上发布。还要小心将鼠标事件标记为已处理。如果输入处理不是自定义控件的一部分,您通常应该避免使用它。
您应该考虑使用 ItemsControl
和 Canvas
作为面板。然后您可以将绘图移动到标记并为 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 = ...;
}
}
我现在真的很绝望。我只是不能再进一步了,原则上它不应该那么困难。我在过去两周尝试解决它。 以下task/problem: 我的 C# WPF 项目中有一个名为“MarkPointsMap”的 canvas,上面有不同类型的标记点(3 种不同颜色的矩形)。一个 MarkPointsMap 可以包含大约 3000-4000 个不同的 MarkPoints(Children of that canvas)遍布整个 MarkPointsMap。 该 MarkPoints 的位置是从 .tab-file 加载的,它被转换成一个名为“MarkPoints”的列表,并在加载相应的 .tab-file.
这是 MarkPointsMap 的屏幕截图:
有例如大多数是小矩形(绿色的),一些中间的矩形(黄色的)和两个大矩形(红色的)。应使用 selection-rectangle 选择多个标记点。在我的项目中,我已经可以绘制选择矩形,但是“if this.selectRect.Contains(MarkPointsMap.Children)”(见下文)部分不起作用。
selection-rectangle 看起来如下:
程序中加载.tab文件后调用的drawMarkPoints方法在canvas“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);
}
}
}
selection-rectangle是在canvas“MarkPointsMap”中绘制的,三个Mouse-Events(MarkPointsMap_MouseDown、MarkPointsMap_MouseMove、MarkPointsMap_MouseUp) :
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”
}
}
}
为什么这行不通?我想这与从矩形(System.Windows.Shapes 使用描述符)到结构 Rect 的转换有关:IFormattable。
未达到的“if (selectRect.Contains(itemRect)”应该在透视中将selection-rectangle内的所有标记点着色为红色,然后计算点(x-Coordinate, y-Coordinate) 的 selection-rectangle 的 middle-point 并将这个中间点添加回原来的 .tab-file.
任何想法或提示,我该如何继续?提前致谢。
此致!
看来你的计算有误。您正在抵消 selectRect
。您将它相对于呈现的 manualDragRect
居中。这样,您测试的区域与您通过渲染选择边界定义的区域完全不同。
此外,您在 Canvas
上捕获鼠标,但在某些不同的控件上释放捕获。它也应该在 MarkPointsMap
上发布。还要小心将鼠标事件标记为已处理。如果输入处理不是自定义控件的一部分,您通常应该避免使用它。
您应该考虑使用 ItemsControl
和 Canvas
作为面板。然后您可以将绘图移动到标记并为 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 = ...;
}
}