всплывающее окно wpf не закрывается автоматически, когда datagrid внутри всплывающего окна захватывает мышь

#c# #wpf #popup #grid #mousecapture

#c# #wpf #всплывающее окно #сетка #mousecapture

Вопрос:

У меня есть всплывающее окно с 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 в требуемом обработчике событий элемента управления ‘misbehaving’ и программно сделал то, что я хотел сделать с ним.

Это не очень хорошее решение и не решает всех проблем, но вы можете попробовать. Обязательно прокомментируйте, что вы сделали, потому что это может привести к беспорядку.

Ответ №4:

у меня была такая же проблема, и я сделал что-то вроде этого:

  private void YourDataGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
         YourDataGrid.CaptureMouse();
         YourDataGrid.ReleaseMouseCapture();
    }
  

но я ищу что-нибудь получше…