Кнопки «Свернуть», «Развернуть» и «Закрыть» в строке заголовка Windows не работают одним щелчком мыши, когда открыто всплывающее окно - PullRequest
0 голосов
/ 26 апреля 2018

Когда мое всплывающее окно открыто, первый единственный щелчок по кнопке сворачивания, разворачивания или закрытия не работает.Первый щелчок по этим кнопкам панели заголовка закрывает всплывающее меню и смещает фокус, а затем по второму щелчку минимизирует / максимизирует / закрывает окно работ.

Есть ли способ - где мы можем активировать эти заголовкипанель кнопок на первый клик сама?

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

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

1 Ответ

0 голосов
/ 26 апреля 2018

То, что вы пытаетесь достичь, нарушает «нормальное» поведение Windows.На самом деле, это управляется операционной системой.

Но если вы все еще хотите переопределить поведение операционной системы по умолчанию, вам нужно сделать магию сообщений Windows низкого уровня.

У меня естьрешение для вас, это простое прикрепленное свойство, которое вы можете использовать для всех ваших Popup s.Вот так:

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

Однако что-то происходит за кулисами, поэтому я попытаюсь объяснить это.Вот полный источник прикрепленной собственности, которую я создал для вас.Прочитайте комментарии, чтобы понять, что происходит.

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;
    }
}

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...