canton7 / Stylet

A very lightweight but powerful ViewModel-First MVVM framework for WPF for .NET Framework and .NET Core, inspired by Caliburn.Micro.
MIT License
981 stars 143 forks source link

`ShowMessageBox` freeze primary window when show a message box on secondary windows #374

Open VShawn opened 1 year ago

VShawn commented 1 year ago

Description

When call IoC.Get<IWindowManager>().ShowDialog or IoC.Get<IWindowManager>().ShowMessageBox on secondary window, the primary window will be freezen.

With ShowDialog provide by the runtime, primary window works fine.

To Reproduce Code to reproduce the bug, which someone else can run.

Version Info

Additional Info

With stylet messagebox:

1

1

With system messagebox:

1

Here is the code related:

https://github.com/1Remote/PRemoteM/blob/dev_net6/Ui/View/Host/TabWindowViewModel.cs#L236-L237

https://github.com/1Remote/PRemoteM/blob/58805bd0bb59757e9016a89cdfd14300a64278b7/Ui/Utils/MessageBoxHelper.cs#L26-L33

And you can get the exe file from: https://github.com/1Remote/PRemoteM/releases

VShawn commented 1 year ago
    var window = new InputWindow
    {
        Title = "title",
        Prompt = "Hi, test native owner window",
        Response = "",
        Result = Results.Cancel,
        ShowInTaskbar = false,
    };
    window.Owner = this;
    window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
    window.ShowDialog();

this above will open a modal dialog to freeze both two window.

So using the native func ShowDialog to show a windows will freeze all of the windows.

Then I noted WindowManager.ShowMessageBox based on native ShowDialog.

That's the reason why WindowManager.ShowMessageBox freeze my two windows.

@canton7 can we make WindowManager.ShowMessageBox a same behaviour like native MessageBox.Show ?

VShawn commented 1 year ago

I have find a workaround for this ticket. I will make a PR for this latter.

  var mbvm = new MessageBoxViewModel();
  mbvm.Setup("Hi, test stylet message box");
  if (IoC.Get<IViewManager>().CreateAndBindViewForModelIfNecessary(mbvm) is Window window)
  {
      window.Owner = this;
      window.Loaded += (o, args) =>
      {
          var dlgWindow = o as Window;
          // dlg don't have a Owner
          if(dlgWindow?.Owner == null)
              return;
          var windows = Application.Current.Windows;
          // enable the window != Owner
          foreach (Window w in windows)
          {
              if (w == dlgWindow.Owner) continue;
              if (w is { IsLoaded: true })
              {
                  if (HwndSource.FromVisual(w) is HwndSource hwndSource)
                      EnableWindow(hwndSource.Handle, true);
              }
          }
      };
      window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
      window.ShowDialog();
  }