当popup中的datagrid捕获鼠标时,wpf弹出窗口不会自动关闭

时间:2011-04-27 16:57:16

标签: c# wpf popup grid 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事件上添加一个处理程序,以便通过弹出窗口捕获鼠标,但它似乎并不那么容易。有什么想法吗?

4 个答案:

答案 0 :(得分:4)

也许它会有所帮助。 附加行为:

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>

答案 1 :(得分:2)

我认为你偶然发现了一个普通的老虫。我已经复制了这个,但找不到一种合理的方法让它运转起来。我认为你应该向微软提交一个错误。它似乎是一个捕获鼠标的组件,并且它不会将捕获恢复到最初的捕获组件。

答案 2 :(得分:2)

我最近遇到了类似的问题,尽管不完全相同,而且它出现在Silverlight中。我通过使用GetTemplatedParent函数在“行为不端”控件的必需事件处理程序中搜索所需的控件(在我的情况下是弹出窗口)来破解我的方式,并以编程方式执行我想要对其执行的操作。

这不是一个很好的解决方案,并没有解决所有问题,但你可以尝试一下。一定要评论你做了什么,因为它可能变得一团糟。

答案 3 :(得分:0)

我有同样的问题,并做了类似的事情:

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

但我正在寻找更好的东西......

相关问题