XAML 当用户在作为ShowDialog启动的窗口外单击时显示消息

2ul0zpep  于 2022-12-07  发布在  其他
关注(0)|答案(3)|浏览(150)

我有一个示例Wpf应用程序,我从全屏启动的主窗口中启动一个窗口。每当用户单击启动的子窗口之外时,我都希望显示一个消息框。我实际上参考了这篇文章how to close a WPF Dialog Window when the user clicks outside it
但问题是在我的例子中Deactivated只在关闭子窗口时被引发。请帮助我如何实现这一点。编辑:注意我希望ShowDialog,因为我希望子窗口成为阻塞窗口。

private void Button_Click(object sender, RoutedEventArgs e)
        {
            Window w = new Window();
            w.Height = 990;
            w.Width = 1840;
            w.MaxHeight = 990;
            w.Width = 1840;
            w.WindowStartupLocation = WindowStartupLocation.Manual;
            w.Top = this.Height - w.Height;
            w.Left = this.Width - w.Width;
            w.Deactivated += W_Deactivated;
            w.ShowDialog();
        }

        private void W_Deactivated(object sender, EventArgs e)
        {
            MessageBox.Show("You clicked out");
        }
rn0zuynd

rn0zuynd1#

Here I'm using the using System.Windows.Input [InputManager](https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.inputmanager?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Windows.Input.InputManager);k(TargetFrameworkMoniker-.NETFramework%26f%3D255%26MSPPError%3D-2147217396&view=netframework-4.7.2) PreProcessInput event to preview a Mouse input event, filtered by [e.StagingItem.Input](https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.notifyinputeventargs.stagingitem?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Windows.Input.NotifyInputEventArgs.StagingItem);k(TargetFrameworkMoniker-.NETFramework%26f%3D255%26MSPPError%3D-2147217396&view=netframework-4.7.2) , generated on a defined element ( Window ).
Then, calculate the position of a Mouse Left click with element.RestoreBounds.Contains(element.PointToScreen(e.GetPosition(element))) .
If the click is generated outside the element Bounds , the Window shows a message, then closes (or quits the app).
The Mouse capture is activated using [UIElement.CaptureMouse()](https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.capturemouse?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Windows.UIElement.CaptureMouse);k(TargetFrameworkMoniker-.NETFramework%26f%3D255%26MSPPError%3D-2147217396&view=netframework-4.7.2) and released on a MouseDown event with [UIElement.ReleaseMouseCapture](https://learn.microsoft.com/en-us/dotnet/api/system.windows.uielement.releasemousecapture?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Windows.UIElement.ReleaseMouseCapture);k(TargetFrameworkMoniker-.NETFramework&view=netframework-4.7.2) .
It's more or less the same as using [Mouse.Capture()](https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.mouse.capture?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(System.Windows.Input.Mouse.Capture);k(TargetFrameworkMoniker-.NETFramework&view=netframework-4.7.2) .
Note that you can click on your Window controls, but if you drag the Window using its TitleBar , the MouseUp event is not rised (by default it's eaten).
If this is an issue, create a logic that detects whether the mouse event was generated in that area and restore the capture after the MouseDown has completed.

using System.Windows;
using System.Windows.Input;

public partial class YourWindow : Window
{
    MouseCapturePreview MouseCaptureHandler;
    //(...)

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        MouseCaptureHandler = new MouseCapturePreview(this);
        //(...)
    }

    public class MouseCapturePreview
    {
        public MouseCapturePreview(Window element)
        {
            InputManager.Current.PreProcessInput += (s, e) => {
                if (e.StagingItem.Input is MouseButtonEventArgs)
                    Handler(s, (MouseButtonEventArgs)e.StagingItem.Input);
            };

            void Handler(object sender, MouseButtonEventArgs e)
            {
                Console.WriteLine("Event Received");
                if (e.LeftButton == MouseButtonState.Pressed) {
                    Console.WriteLine("Mouse Released");
                    element.ReleaseMouseCapture();
                    Mouse.Capture(element);
                    if (!element.RestoreBounds.Contains(element.PointToScreen(e.GetPosition(element))))
                    {
                        Console.WriteLine("Clicked outside");
                        MessageBox.Show("You clicked outside, time to close.");
                        //Application.Current.Shutdown();
                        element.Close();
                    }
                } else {
                    Console.WriteLine("Mouse Captured");
                    element.CaptureMouse();
                }
            }
        }
    }

    private void Window_Activated(object sender, EventArgs e)
    {
        Console.WriteLine("Activated");
        this.CaptureMouse();
    }
}
3wabscal

3wabscal2#

我发现了另一种方法,只需完成几个步骤。您可以在子视图中创建一个父视图的事件处理程序......并且不要调用ShowDialog(),只需调用Dialog()
这是父窗口,一旦子窗口打开,您就不应该在其中单击。

public partial class Parent : Window
{
    private void OpenDialog_Clicked(object sender, RoutedEventArgs e)
    {
          Child child = new Child(this);
          child.Show();
    }
}

这是子窗口,用作对话框并防止用户单击父窗口。

public partial class Child : Window
{
    private Parent _parent;

    public Child(Parent parent)
    {
        InitializeComponent();
        _parent = parent;
        parent.PreviewMouseDown += new MouseButtonEventHandler(this.ParentWindow_PreviewMouseDown);       
        this.Closed += new System.EventHandler(this.Window_Closed);         
    }

    // If you click the parent, you get a message and child window will be top most again
    private void ParentWindow_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        MessageBox.Show("na ah");
        this.Topmost = true;
    }

    // If you forget this, you will keep getting that "na ah" message even after closing child window.
    private void Window_Closed(object sender, EventArgs e)
    {
        _parent.PreviewMouseDown -= new MouseButtonEventHandler(ParentWindow_PreviewMouseDown);
    }
}
hm2xizp9

hm2xizp93#

用途

w.Show();

因为前面的对话框是模式对话框(Showdialog()),所以在关闭它之前不能继续。

相关问题