4

I have 2 windows. Lets call them A and B. A is opening B with a ShowDialog(). So I am opening B - When the user minimizes B or gets it into the back somehow and he tries clicking window A again its blocked (as it should be), but is there an Event that I can catch up onto when this happens ?

I am trying to achieve bringing the blocking window B into the front when hes trying to access window A with window B opened.

Codeexample:

Thats how Window A is opened from the Mainwindow

            WindowA windowA = new WindowA();

            windowA.Owner = Application.Current.MainWindow;

            windowA.Show();
            windowA.Activate();

And thats how Window B is opened

            WindowB windowB = new WindowB();
            windowB.Owner = this; //(this = windowA)
            windowB.ShowDialog();

Both windows have no special properties set except

WindowStartupLocation="CenterScreen"
  • It sounds like you're not setting B's `Owner` property to A? – Mark Feldman May 02 '19 at 09:04
  • I rechecked it but I already set the Owner before the ShowDialog() – Tanner Hall May 02 '19 at 09:13
  • 1
    So I guess we are talking about a modal dialog, right? Would you mind adding a [mcve]? So we can see how exactly your Dialog relates to the opening Form and what you are setting and what not? – Fildor May 02 '19 at 09:42
  • http://www.filedropper.com/sotestapp I uploaded the testapplication here. You can just click threw the Middlebutton on the application -> then minimize Window B then open Window A again. Now Window A is blocking and i want to show B again when A is Blocking – Tanner Hall May 02 '19 at 10:50
  • 2
    @TannerHall: Don't upload your sample to an external site. Post it here. – mm8 May 02 '19 at 13:28
  • @mm8 this will probably get hate, but I haven't found the possibility to upload a zip-file directly in here and even when I checked online for how to do that - everything i find is you can't and people said use dropbox etc. – Tanner Hall May 02 '19 at 13:39
  • 2
    You shouldn't upload a .zip file but edit your question to include code snipperts that make up a [MCVE](https://stackoverflow.com/help/mcve). – mm8 May 02 '19 at 13:43
  • @mm8 i edited my ticket - thank you – Tanner Hall May 02 '19 at 13:53

2 Answers2

2

There is no managed event being raised when you click outside of a modal window but you should be able to handle this in the modal window using some p/invoke. Here is an example for you:

public sealed partial class ModalWindow : Window, IDisposable
{
    [DllImport("User32.dll")]
    public static extern IntPtr SetWindowsHookEx(int idHook, HookDelegate lpfn, IntPtr hmod, int dwThreadId);

    [DllImport("User32.dll")]
    public static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("User32.dll")]
    public static extern IntPtr UnhookWindowsHookEx(IntPtr hHook);

    [DllImport("user32.dll")]
    public static extern bool GetCursorPos(out POINT lpPoint);

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public static implicit operator Point(POINT point)
        {
            return new Point(point.X, point.Y);
        }
    }

    public delegate IntPtr HookDelegate(int code, IntPtr wParam, IntPtr lParam);

    private const int WH_MOUSE_LL = 14;
    private const int WM_LBUTTONDOWN = 0x0201;
    private HookDelegate mouseDelegate;
    private IntPtr mouseHandle;

    public ModalWindow()
    {
        InitializeComponent();
        mouseDelegate = MouseHookDelegate;
        mouseHandle = SetWindowsHookEx(WH_MOUSE_LL, mouseDelegate, IntPtr.Zero, 0);
    }

    private IntPtr MouseHookDelegate(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code < 0)
            return CallNextHookEx(mouseHandle, code, wParam, lParam);

        switch ((int)wParam)
        {
            case WM_LBUTTONDOWN:
                POINT lpPoint;
                GetCursorPos(out lpPoint);
                if (lpPoint.X < Left || lpPoint.X > (Left + Width) || lpPoint.Y < Top || lpPoint.Y > (Top + Height))
                {
                    //Outside click detected...
                }
                break;
        }

        return CallNextHookEx(mouseHandle, code, wParam, lParam);
    }

    protected override void OnClosed(EventArgs e)
    {
        Dispose();
        base.OnClosed(e);
    }

    public void Dispose()
    {
        if (mouseHandle != IntPtr.Zero)
            UnhookWindowsHookEx(mouseHandle);
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
1

If you want to restore second window when it is minimized and user does click on first(blocked) window, then you can go this way(add this code to the WindowB):

public WindowB()
{
    PreviewMouseDown += WindowB_PreviewMouseDown;
    StateChanged += WindowB_StateChanged;
    InitializeComponent();
    LostMouseCapture += WindowB_LostMouseCapture;

}

private void WindowB_LostMouseCapture(object sender, MouseEventArgs e)
{
    //You can also evaluate here a mouse coordinates.
    if (WindowState == WindowState.Minimized)
    {
        e.Handled = true;
        CaptureMouse();
    }
}

private void WindowB_StateChanged(object sender, EventArgs e)
{
    if (WindowState== WindowState.Minimized)
    {
        CaptureMouse();
    }
    else
    {
        ReleaseMouseCapture();
    }
}

private void WindowB_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    WindowState = WindowState.Normal;
    Debug.WriteLine("WindowB PreviewMouseDown");
}

So you have to start mouse capturing on second window on it being minimized, for if user does click on WindowA this can be handled on WindowB.
As window being minimized it going to lost a mouse capture(therefore you have to listen on LostMouseCapture), that you have to prevent.

Left mouse button down on WindowA does restore thenWindowB.

Rekshino
  • 6,954
  • 2
  • 19
  • 44