Мое решение немного похоже на ShawnFeatherly, но без TouchFrame.
По сути, как он говорит, если вы вызываете MouseCapture из сетки, где произошло событие MouseDown, MouseUp будет запущен в той же сетке. Таким образом, мы знаем, как получать уведомления при возникновении MouseUp, осталась только одна проблема - как узнать, в какой сетке фактически произошло MouseUp.
Для этого мы будем использовать метод VisualTreeHelper.FindElementsInHostCoordinates
, поскольку он возвращает все элементы по указанной координате.
Итак, сначала добавьте обработчик события MouseLeftButtonDown к каждой из ваших сеток:
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
((Grid)sender).CaptureMouse();
}
Теперь в обработчике события MouseLeftButtonUp каждой из ваших сеток сначала отпустите захват мыши, а затем извлеките сетку, в которой произошел MouseUp:
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var grid = (Grid)sender;
grid.ReleaseMouseCapture();
var mouseUpGrid = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Grid>()
.FirstOrDefault();
if (mouseUpGrid != null)
{
Debug.WriteLine("MouseUp in " + mouseUpGrid.Name);
mouseUpGrid.Background = new SolidColorBrush(Colors.Red);
}
}
Обратите внимание, что проблема может возникнуть в зависимости от вашего визуального дерева: если у вас несколько сеток и вы хотите обнаруживать MouseUp только на некоторых, вам нужен способ их идентификации. Для этого я предлагаю использовать свойство Tag
. Тег - это универсальное поле, доступное для каждого элемента управления, которое вы можете использовать по своему усмотрению. Это особенно полезно для целей идентификации.
Начните с добавления его в сетку, которая вас интересует:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0"
MouseLeftButtonUp="ContentPanel_MouseLeftButtonUp">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="g1"
Background="Green"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
<Grid x:Name="g2"
Grid.Row="1"
Background="Blue"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
</Grid>
Затем используйте точно такую же логику для кода, но на этот раз добавьте фильтр при просмотре визуального дерева:
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var grid = (Grid)sender;
grid.ReleaseMouseCapture();
var mouseUpGrid = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Grid>()
.FirstOrDefault(element => element.Tag is string && (string)element.Tag == "dragdrop");
if (mouseUpGrid != null)
{
Debug.WriteLine("MouseUp in " + mouseUpGrid.Name);
mouseUpGrid.Background = new SolidColorBrush(Colors.Red);
}
}
И все готово! Этот код должен быть в состоянии обрабатывать сложные сценарии, такие как:
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0"
MouseLeftButtonUp="ContentPanel_MouseLeftButtonUp">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid x:Name="g1"
Background="Green"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
<Grid x:Name="DummyGrid" Grid.Row="1">
<Grid x:Name="g2"
Background="Blue"
MouseLeftButtonDown="Grid_MouseLeftButtonDown"
MouseLeftButtonUp="Grid_MouseLeftButtonUp"
Tag="dragdrop" />
</Grid>
</Grid>