1
votes

In WPF Prism 7.2 I have followed the IDialogService instructions shown here.

I have a PlotsDialogPanel UserControl with a single ContentControl as shown here:

<UserControl x:Class="PlotModule.Dialogs.Views.PlotsDialogPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True"
             xmlns:local="clr-namespace:PlotModule.Dialogs.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <prism:Dialog.WindowStyle>
        <Style TargetType="Window">
            <Setter Property="prism:Dialog.WindowStartupLocation" Value="CenterScreen" />
            <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
            <Setter Property="ShowInTaskbar" Value="True"/>
        </Style>
    </prism:Dialog.WindowStyle>

    <Grid>
        <ContentControl prism:RegionManager.RegionName="PlotsDialogDisplayRegion" />
    </Grid>
</UserControl>

In my PlotModule RegisterTypes method I register the dialog:

public void RegisterTypes(IContainerRegistry containerRegistry)
{
   containerRegistry.RegisterDialog<PlotsDialogPanel, PlotsDialogPanelViewModel>();
}

But when the dialog is shown in an event handler it acts as modal, it is always topmost on the parent.

private void MainMenuEventHandler(string inParameter)
{
   _DialogService.Show("PlotsDialogPanel", new DialogParameters(), r => {});
}

I can't see what I am doing wrong here, any ideas on why the dialog is behaving as a modal? Everything else works as expected and the dialog shows and closes with the IDialogAware::OnDialogOpened and OnDialogClosed functioning as expected.

1

1 Answers

0
votes

It is not actually modal, just the top most window. A modal dialog is shown using the ShowDialog method an will not only be the top most window, but also disable any user interaction with its owner window until dismissed.

The reason for a dialog being on top of another window is that it has an owner window assigned to its Owner property. By default, Prism will always assign the first active window in the application as the owner of the dialog, unless you have set an owner that is not null explictly on the dialog host window.

See the implementation for DialogService on GitHub for reference. This line sets the Owner of a dialog.

if (window.Owner == null)
   window.Owner = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);

Since this is the way that the DialogService is implemented, you have to create your own dialog service and change the behavior. You could for example provide an overload to not set an owner. Implement the original IDialogService interface to provide compatibility to the default implementation.

public interface ICustomDialogService : IDialogService
{
   public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback);
}

Create a type CustomDialogService derived from ICustomDialogService and copy the original implementation from GitHub. Adapt the original methods by passing down a parameter to the ConfigureDialogWindowProperties method to determine whether to set an Owner or not and act accordingly.

public class CustomDialogService : ICustomDialogService
{
   // ...other public members.

   public void ShowOrphan(string name, IDialogParameters parameters, Action<IDialogResult> callback)
   {
      // Appended a new parameter "isOrphan"
      ShowDialogInternal(name, parameters, callback, false, true);
   }

   // ...other private members.

   // Appended a new parameter "isOrphan"
   void ConfigureDialogWindowProperties(IDialogWindow window, FrameworkElement dialogContent, IDialogAware viewModel, bool isOrphan)
   {
      // ...other code.

      if (isOrphan)
         return;

      if (window.Owner == null)
         window.Owner = System.Windows.Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive);
   }
}

Register the custom dialog service with your interface and the original interface so you can use both.

containerRegistry.RegisterSingleton <CustomDialogService>();
containerRegistry.Register<IDialogService, CustomDialogService>();
containerRegistry.Register<ICustomDialogService, CustomDialogService>();

There might be other workarounds like creating a custom dialog host window that ignores the Owner property or other hacks, but I think that creating a custom dialog service is the cleanest approach here.