Всплывающее окно wpf не закрывается автоматически, когда datagrid внутри всплывающего окна захватывает мышь
У меня есть всплывающее окно с StaysOpen=False
, поэтому я хочу закрыть его, щелкнув везде вне всплывающего окна. Внутри всплывающего окна есть DataGrid
. Если я открою всплывающее окно, а затем щелкните в другом месте, всплывающее окно будет закрыто. Но этого не произойдет, если перед щелчком вне всплывающего окна я нажму на заголовок столбца в DataGrid
. Тест XAML:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black">
<Grid>
<ToggleButton x:Name="btn" VerticalAlignment="Top">Open</ToggleButton>
<Popup StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=btn}" >
<DataGrid Width="150" Height="150">
<DataGrid.Columns>
<DataGridTextColumn Header="Column" />
</DataGrid.Columns>
</DataGrid>
</Popup>
</Grid>
</Window>
Я думаю, что это происходит потому, что заголовок столбца захватывает мышь при щелчке, а всплывающее окно больше не принимает события мыши. Я попытался добавить обработчик на событие LostMouseCapture
, чтобы захватить мышь назад всплывающим меню, но, похоже, это не так просто. Любые идеи?
Ответы
Ответ 1
Может, это поможет.
Прикрепленное поведение:
public class DataGridColumnHeaderReleaseMouseCaptureBehavior {
public static DataGrid GetReleaseDGCHeaderBehavior(DependencyObject obj) {
return (DataGrid)obj.GetValue(ReleaseDGCHeaderBehaviorProperty);
}
public static void SetReleaseDGCHeaderBehavior(DependencyObject obj, Boolean value) {
obj.SetValue(ReleaseDGCHeaderBehaviorProperty, value);
}
public static readonly DependencyProperty ReleaseDGCHeaderBehaviorProperty =
DependencyProperty.RegisterAttached("ReleaseDGCHeaderBehavior",
typeof(DataGrid),
typeof(DataGridColumnHeaderReleaseMouseCaptureBehavior),
new UIPropertyMetadata(default(DataGrid), OnReleaseDGCHeaderBehaviorPropertyChanged));
private static Popup _popup;
private static void OnReleaseDGCHeaderBehaviorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var oldGrid = (DataGrid)e.OldValue;
if (oldGrid != null)
oldGrid.MouseLeave -= OnMouseLeave;
var refSender = d as Popup;
_popup = refSender;
if (refSender != null) {
var refGrid = e.NewValue as DataGrid;
if (refGrid != null) {
refGrid.MouseLeave += OnMouseLeave;
}
}
}
static void OnMouseLeave(object sender, MouseEventArgs args) {
if (_popup != null)
typeof(Popup).GetMethod("EstablishPopupCapture", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Invoke(_popup, null);
}
}
XAML:
<Popup x:Name="popup"
bhvrs:DataGridColumnHeaderReleaseMouseCaptureBehavior.ReleaseDGCHeaderBehavior="{Binding ElementName=dataGrid}">
<DataGrid x:Name="dataGrid"/>
</Popup>
Ответ 2
Я думаю, вы наткнулись на просто старый баг. Я воспроизвел это и не смог найти разумный способ заставить его работать. Я думаю, вы должны сообщить об ошибке в Microsoft. Похоже, что компонент, который захватывает мышь, и его блокирует, он не восстанавливает захват для первоначально захваченного компонента.
Ответ 3
Недавно у меня была аналогичная проблема, но не совсем то же самое, и это было в Silverlight. Я взломал свой путь через него, выполнив требуемый контроль (в вашем случае всплывающее окно, которое я предполагаю) с функцией GetTemplatedParent, в требуемом обработчике событий "неправильного поведения" и программно сделайте то, что я хотел сделать на нем.
Это нехорошее решение и не решает все проблемы, но вы можете попробовать. Обязательно прокомментируйте, что вы сделали, потому что это может превратиться в беспорядок.
Ответ 4
У меня была та же проблема, и я сделал что-то вроде этого:
private void YourDataGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
YourDataGrid.CaptureMouse();
YourDataGrid.ReleaseMouseCapture();
}
но я ищу еще кое-что еще...