首页 > 解决方案 > 检测按钮是否在绘制的矩形框内

问题描述

我有一个带有矩形框的画布,用于选取框,我的 uniformgrid 包含动态生成的按钮。

选框选择工具现在正在工作,即我可以看到它被绘制在统一网格上,并且我已经根据示例代码获得了 mousedown 位置和 mouseup 位置:

在 WPF 中单击并拖动选择框

我的 XAML 是这样的:

<Grid Name="mainGrid" DockPanel.Dock="Top"  Width="800" Height="400">
    <Rectangle x:Name="selectionBox" Visibility="Collapsed" Stroke="White" StrokeThickness="4" StrokeDashArray="2,1"/>
    <UniformGrid DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="uniformGrid" Grid.Row="1" Width="{Binding Width, ElementName=mainGrid}" Height="{Binding Height, ElementName=mainGrid}"
Rows="{Binding RowCount}"
Columns="{Binding ColumnCount}" MouseDown="UniformGrid_MouseDown" MouseUp="UniformGrid_MouseUp" MouseMove="UniformGrid_MouseMove" Background="Transparent">
    </UniformGrid>
    <Canvas Name="buttonCanvas">
    </Canvas>
</Grid>

问题是,我不确定如何检查我的按钮(它们是 UniformGrid 的子项)是否包含/部分包含在此矩形中。

标签: c#wpf

解决方案


这是对您链接的解决方案的扩展。

以下是一种方法,它将确定给定按钮在给定MouseUp位置MouseDown内。在该示例中,有一个名为 的成员变量mouseDownPos和一个名为 的局部变量mouseUpPos,它们分别注册了这些变量。因此,在Grid_MouseUp事件处理程序中,我将添加以下代码来获取Button您的所有控件Canvas,迭代它们中的每一个并将它们传递给一个方法以查看它是否在所述区域内。

private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
    // Release the mouse capture and stop tracking it.
    mouseDown = false;
    theGrid.ReleaseMouseCapture();

    // Hide the drag selection box.
    selectionBox.Visibility = Visibility.Collapsed;

    Point mouseUpPos = e.GetPosition(theGrid);

    // TODO: 
    //
    // The mouse has been released, check to see if any of the items 
    // in the other canvas are contained within mouseDownPos and 
    // mouseUpPos, for any that are, select them!
    //
    var buttons = canvasButtons.Children.OfType<System.Windows.Controls.Button>();

    foreach (var button in buttons)
    {
        var isInSelection = IsInsideSelection(mouseDownPos, mouseUpPos, button);
    }
}

IsInsideSelection()是我编写的一个函数,它询问矩形的鼠标上下位置以及Button控件。

private bool IsInsideSelection(Point mouseDown, Point mouseUp, System.Windows.Controls.Button button)
{
    // This grabs the coordinates of the button, relative to the main window. 
    // If you would like it relative to something else, like your canvas or the grid, you'd have to pass appropriate control to the `TransformToAncestor()` function.
    var buttonPos = button.TransformToAncestor(mainWin).Transform(new Point(0, 0));

    // Bottom right corner coordinates of the button control.
    var btnBottomRight = new Point(buttonPos.X + button.Width, buttonPos.Y + button.Height);

    // If button X and Y (which is the top left corner of the button) 
    // are outside the mouse down position, it's not inside the rectangle 
    if (buttonPos.X < mouseDown.X || buttonPos.Y < mouseDown.Y)
        return false;

    // If X and Y of button bottom right corner is outside mouse up coordinates,
    // then the control is again outside the rectangle
    if (btnBottomRight.X > mouseUp.X || btnBottomRight.Y > mouseUp.Y)
        return false;

    // Everything else, control is inside
    return true;
}

笔记:

  • 这会获取按钮相对于主窗口的坐标。如果你希望它相对于其他东西,比如你的画布或网格,你必须将适当的控制传递给TransformToAncestor()函数。

编辑

仅当矩形是从左到右绘制时,上述函数才有效。要处理从右到左的情况,您可以上下切换鼠标位置,如下所示:

private bool IsInsideSelection(Point mouseDown, Point mouseUp, System.Windows.Controls.Button button)
{
    if (mouseUp.X < mouseDown.X)
    {
        var temp = mouseUp;
        mouseUp = mouseDown;
        mouseDown = temp;
    }

    var buttonPos = button.TransformToAncestor(mainWin).Transform(new Point(0, 0));
    var btnBottomRight = new Point(buttonPos.X + button.Width, buttonPos.Y + button.Height);

    if (buttonPos.X < mouseDown.X || buttonPos.Y < mouseDown.Y)
        return false;

    if (btnBottomRight.X > mouseUp.X || btnBottomRight.Y > mouseUp.Y)
        return false;

    return true;
}

编辑2:

以下是XAML我的测试应用程序,我在UniformGrid这里使用 a 来控制控件。请注意,在检索按钮时,您必须使用名称UniformGrid来执行此操作,在本例中为“unfGrid”。

<Window ...
        Name="mainWin"
        WindowStartupLocation="CenterScreen"
        Title="MainWindow" Height="600" Width="600">
    <Grid x:Name="theGrid"
          MouseDown="Grid_MouseDown"
          MouseUp="Grid_MouseUp"
          MouseMove="Grid_MouseMove"
          Background="Transparent">
        <UniformGrid Name="unfGrid" Grid.Row="0">
            <Button Name="Btn1" Content="Button1" Grid.Row="0"
                        Width="100" Height="24"/>
            <Button Name="Btn2" Content="Button2" Grid.Row="1"
                        Width="100" Height="24"/>
            <Button Name="Btn3" Content="Button3" Grid.Row="2"
                        Width="100" Height="24"/>
            <!-- This canvas contains elements that are to be selected -->
        </UniformGrid>

        <Canvas Grid.Row="0">
            <!-- This canvas is overlaid over the previous canvas and is used to 
            place the rectangle that implements the drag selection box. -->
            <Rectangle
                x:Name="selectionBox"
                Visibility="Collapsed"
                Stroke="Black"
                StrokeThickness="1"/>
        </Canvas>
    </Grid>
</Window>

推荐阅读