打开弹出窗口时,单击一次时Windows标题栏的“最小化",“最大化"和“关闭"按钮不起作用 [英] Minimize, Maximize and close buttons of Windows title bar does not work on single click when pop up window is open

查看:106
本文介绍了打开弹出窗口时,单击一次时Windows标题栏的“最小化",“最大化"和“关闭"按钮不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我的弹出窗口打开时,最小或最大化或关闭按钮的第一次单击不起作用. 第一次点击这些标题栏按钮将关闭弹出菜单并移动焦点, 然后第二次单击窗口工程的最小化/最大化/关闭.

While my popup window is open, The first single click on minimize or maximize or close button does not work. The first Click on these title bar buttons closes the popup menu and shifts the focus, And then on the second click the minimize/maximize/close of window works.

有什么办法-我们可以在第一次单击时激活这些标题栏按钮吗?

Is there any way - where we can activate these title bar buttons on the first click itself ?

MainWindow.xaml

MainWindow.xaml

<Button Height="54" Width="50" Margin="100,0,0,0" x:Name="btnNotification"  FontFamily="Segoe UI Symbol" FontSize="20" Content="&#x1f514;" Command="{Binding LoadNotification}" Click="btnNotification_Click"/>

<Popup Name="NotificationPopup" IsOpen="False" Closed="PopupClosed" StaysOpen="False" PlacementTarget="{Binding ElementName=btnNotification}" Placement="Bottom" VerticalOffset="20">
    <Grid x:Name="PopUpGrid" Height="560" Width="360" Background="White">
        <StackPanel Orientation="Vertical" HorizontalAlignment="Right">
            <Button  BorderBrush="Transparent" BorderThickness="0" Background="White" >
                <StackPanel Width="{Binding ActualWidth, ElementName=PopUpGrid}" Orientation="Vertical">
                    <WrapPanel>
                        <Rectangle Width="20"/>
                        <TextBlock  Text="Notifications" Width="300" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="24" FontWeight="Light" />
                        <Button Click="btnNotification_Click" >
                            <StackPanel>
                                <TextBlock Text="&#x2715;" Foreground="Black" FontWeight="ExtraLight"/>
                            </StackPanel>
                        </Button>
                    </WrapPanel>
                    <Grid>
                            <!--Datagrid-->
                    </Grid>
                </StackPanel>
            </Button>
        </StackPanel>
    </Grid>
</Popup>

MainWindow.xaml.cs

MainWindow.xaml.cs

public void PopupClosed(object sender, EventArgs e)
{
    NotificationPopup.IsOpen = false;               
}

推荐答案

您试图实现的目标违反了Windows的正常"行为.实际上,这是由操作系统管理的.

What you are trying to achieve, violates the 'normal' Windows behavior. Actually, this is managed by the Operating System.

但是,如果您仍然想覆盖默认操作系统的行为,则需要做一些底层Windows消息魔术.

But if you still want to override the default Operating System's behavior, you need to do some low-level Windows' messages magic.

我为您提供了一个解决方案,这是一个简单的附加属性,您可以将其用于所有Popup.就是这样:

I have a solution for you, this is a simple attached property that you can use for all your Popups. Just like that:

<Popup local:PopupMouseEnhance.Enabled="True">
    <!-- your content here -->
</Popup>

但是,幕后发生了一些事情,所以我将尽力对其进行解释.这是我为您创建的附加属性的完整来源.阅读评论以了解发生了什么.

However, there's something going on behind the scenes, so I'll try to explain it. Here is the complete source of the attached property I created for you. Read the comments to understand what's going on.

static class PopupMouseEnhance
{
    // This is the usual attached property stuff...
    public static bool GetEnabled(UIElement element)
    {
        return (bool)element.GetValue(EnabledProperty);
    }

    public static void SetEnabled(UIElement element, bool value)
    {
        element.SetValue(EnabledProperty, value);
    }

    public static readonly DependencyProperty EnabledProperty =
        DependencyProperty.RegisterAttached(
            "Enabled",
             typeof(bool),
             typeof(PopupMouseEnhance),
             new PropertyMetadata(false, EnabledChanged));

    // This method is called when you set the attached property value
    private static void EnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Popup popup = d as Popup;
        if (popup == null)
        {
            // We don't support anything but Popups
            throw new InvalidOperationException("This attached property can only be set on a Popup object.");
        }

        if ((bool)e.NewValue)
        {
            // if the attached property value is 'true', then enable our trick...
            popup.Opened += Popup_Opened;

            // This is to prevent memory leaks when Popups get removed from the visual tree
            popup.Unloaded += Popup_Unloaded;
        }
        else
        {
            // ... otherwise, disable
            popup.Unloaded -= Popup_Unloaded;
            popup.Opened -= Popup_Opened;
        }      
    }

    private static void Popup_Unloaded(object sender, RoutedEventArgs e)
    {
        // When a Popup is completely unloaded, unsubscribe from everything!
        // This event won't be raised on app's shutdown, but in that case
        // we don't bother with memory leaks anyway.
        Popup p = (Popup)sender;
        p.Unloaded -= Popup_Unloaded;
        p.Opened -= Popup_Opened;      
    }

    private static void Popup_Opened(object sender, EventArgs e)
    {
        Popup p = (Popup)sender;

        // Okay, the Popup is shown. Enable our tricks!
        // First, we determine the window we will monitor:
        Window w = Window.GetWindow(p);
        if (w != null)
        {
            // Then, we need a HwndSource instance of that window
            // to be able to insert our custom Message Hook
            HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(w).Handle);
            if (source != null)
            {
                // All set, enable our custom window helper!
                WindowHelper.Enable(source, w, p);
            }
        }
    }

    // Our custom helper class. The magic occurs here.
    private class WindowHelper
    {
        private readonly HwndSource mHwndSource;
        private readonly Window mWindow;

        private WindowHelper(HwndSource hwndSource, Window window)
        {
            mHwndSource = hwndSource;
            mWindow = window;
        }

        public static void Enable(HwndSource hwndSource, Window window, Popup popup)
        {
            // Create an instance of our helper class...
            WindowHelper helper = new WindowHelper(hwndSource, window);

            // ... and set a Message Hook to our custom method.
            hwndSource.AddHook(helper.WndProc);

            // Don't forget to disable the magic, when the popup is closed.
            popup.Closed += helper.Popup_Closed;
        }

        private void Popup_Closed(object sender, EventArgs e)
        {
            // The Popup is closed now - disable all!
            Popup p = (Popup)sender;
            p.Closed -= Popup_Closed;
            mHwndSource.RemoveHook(WndProc);
        }

        // This is our custom Windows messages hook.
        // This method will be called whenever our window receives a message.
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            // We're only interested in the WM_SETCURSOR message.
            // It will be sent to our window when the user moves the mouse
            // cursor around and clicks the mouse buttons.
            if (msg != NativeConstants.WM_SETCURSOR)
            {
                return IntPtr.Zero;
            }

            // Determine the necessary parameters.
            // See MSDN topic on WM_SETCURSOR for details.
            var mouseMessage = ((int)lParam & 0xFFFF0000) >> 16;
            var hitTest = (int)lParam & 0xFFFF;

            switch (hitTest)
            {
                // Only continue if the mouse is over
                // 'minimize', 'maximize', 'close'
                case NativeConstants.HTMINBUTTON:
                case NativeConstants.HTMAXBUTTON:
                case NativeConstants.HTCLOSE:
                    break;

                default:
                    // Otherwise, do nothing.
                    return IntPtr.Zero;
            }

            // If the user clicks outside the Popup,
            // a WM_MOUSEMOVE message will be transmitted via WM_SETCURSOR.
            // So if we've received something other - ignore that.
            if (mouseMessage != NativeConstants.WM_MOUSEMOVE)
            {
                return IntPtr.Zero;
            }

            // We need to perform these actions manually,
            // because the window will not receive the corresponding messages
            // on first mouse click (when the Popup is still open).
            switch (hitTest)
            {
                case NativeConstants.HTMINBUTTON:
                    mWindow.WindowState = WindowState.Minimized;
                    break;

                case NativeConstants.HTMAXBUTTON:
                    mWindow.WindowState = WindowState.Maximized;
                    break;

                case NativeConstants.HTCLOSE:
                    mWindow.Close();
                    break;
            }

            // We always return 0, because we don't want any side-effects
            // in the message processing.
            return IntPtr.Zero;
        }
    }

    private static class NativeConstants
    {
        public const int WM_SETCURSOR = 0x020;
        public const int WM_MOUSEMOVE = 0x200;

        public const int HTMINBUTTON = 8;
        public const int HTMAXBUTTON = 9;
        public const int HTCLOSE = 20;
    }
}

希望这会有所帮助!

这篇关于打开弹出窗口时,单击一次时Windows标题栏的“最小化",“最大化"和“关闭"按钮不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆