This is an expansion to the solution you've linked.
Following is a method that will decided a given button is inside the given MouseUp
and MouseDown
position. In that example, there's a member variable called mouseDownPos
, and a local variable called mouseUpPos
, which registers each of those. So, inside the Grid_MouseUp
event handler, I'd add the following code to grab all the Button
controls in your Canvas
, iterate each of them and pass them to a method to see if it's inside the said area.
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);
}
}
The IsInsideSelection()
is a function that I wrote, which asks for the mouse up and down positions of the rectangle, and for the Button
control.
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;
}
NOTE:
- 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.
EDIT
The above function only works if the rectangle was drawn left-to-right. To handle the right-to-left scenario, you can switch the mouse up and down positions, like so:
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;
}
EDIT 2:
Following is the XAML
of my test app, and I'm using a UniformGrid
to hold controls here. Note that when retrieving buttons, you must use the name of the UniformGrid
to do so, in this case, '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>