none
Common Dialogs aren't behaving like truly modal dialoges

    Question

  • Hi. If I show the OpenFileDialog after while I have a modeless child WPF Window up, I can't click on the main Window but I can click and interact with the other child Window. Is there a way to make the common dialog act truly modal? Can someone also show me how to get its handle?

    Thanks.

    private void button1_Click(object sender, RoutedEventArgs e)
    {
     Window1 win1 = new Window1();
     win1.Owner = this;
     win1.Show();
    }
    
    private void button2_Click(object sender, RoutedEventArgs e)
    {
     Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
     dlg.FileName = "Document"; // Default file name
     dlg.DefaultExt = ".txt"; // Default file extension
     dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
    
     // Show open file dialog box
     Nullable<bool> result = dlg.ShowDialog(this);
    }

     



    Wednesday, June 01, 2011 12:57 AM

Answers

  • Here is the Helper class along with an implementation, i should mention that on further testing the user can still move other windows but they cannot do anything in them and all windows of the application will always be behind the dialog. In order to prevent the window title bar selection from moving the window you will probably need to get into some interop calls and handlers using user32.dll. You should be able to extend what is provided here if you need to.

     

    <Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication4="clr-namespace:WpfApplication4" Title="MainWindow" Height="350" Width="525">
      <UniformGrid>
        <Button x:Name="btnOpenWindow" Click="btnOpenWindow_Click">Open Window</Button>
        <Button x:Name="btnOpenDialog" Click="btnOpenDialog_Click">Open Dialog</Button>
      </UniformGrid>
    </Window>
    
    

    namespace WpfApplication4 {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
    public MainWindow() {
    InitializeComponent();
    }
    
    private void btnOpenWindow_Click(object sender, RoutedEventArgs e) {
    MainWindow window = new MainWindow();
    window.Show();
    }
    
    private void btnOpenDialog_Click(object sender, RoutedEventArgs e) {
    OpenFileDialog dialog = new OpenFileDialog();
    
    if (ModalDialogHelper.ShowDialog(dialog, Window.GetWindow(this)) == true) {
    // perform logic as usual, dialog will have its properties set
    }
    }
    }
    }
    

    namespace WpfApplication4 {
    public static class ModalDialogHelper {
    private static bool _isDialogOpen;
    
    public static bool IsDialogOpen {
    get { return _isDialogOpen; }
    }
    
    public static bool? ShowDialog(CommonDialog dialog, Window currentWindow) {
    bool? result;
    try {
    Application.Current.MainWindow = currentWindow;
    HookWindowActivatedEvents();
    _isDialogOpen = true;
    result = dialog.ShowDialog();
    }
    finally {
    _isDialogOpen = false;
    UnhookWindowsActivatedEvents();
    }
    
    return result;
    }
    
    private static void UnhookWindowsActivatedEvents() {
    foreach (var obj in Application.Current.Windows) {
    var window = obj as Window;
    if(window != null) {
    window.IsHitTestVisible = true;
    window.Activated -= Window_Activated;
    }
    }
    }
    
    private static void HookWindowActivatedEvents() {
    foreach (var obj in Application.Current.Windows) {
    var window = obj as Window;
    if(window != null) {
    window.IsHitTestVisible = false;
    window.Activated += Window_Activated;
    }
    }
    }
    
    private static void Window_Activated(object sender, EventArgs e) {
    if (IsDialogOpen) {
    Application.Current.MainWindow.Activate();
    }
    }
    }
    }
    

     

    Goodluck and i hope this helps.

    Thursday, June 02, 2011 10:19 PM

All replies

  • Hey VanEsch,

    I thought i had an answer for you and that it had to do with the MainWindow property of the application, but after testing it turns out this is not solved by setting that property.

    I did solve the issue in a test app but its not that great, in lieu of a better idea here is what i did.

    Create a static property that will be shared in your app

    public static bool ModalDialogIsOpen { get; set; }
    

    Make the main window the current window and set the static property when you open a dialog

    Application.Current.MainWindow = Window.GetWindow(this);
          OpenFileDialog d = new OpenFileDialog();
          Globals.ModalDialogIsOpen = true;
          d.ShowDialog();
          Globals.ModalDialogIsOpen = false;
    

    Override OnActivated on the window, when the window is selected if a dialog is open the main window that opened the dialog will be re-selected instead.

     

    protected override void OnActivated(EventArgs e)
        {
          if (Globals.ModalDialogIsOpen)
          {
            Application.Current.MainWindow.Activate();
          }
        }
    

     

    Obviously this can be cleaned up and put into a class that will encapsulate this same logic for all windows, but its a start. Hopefully someone else has a better solution.

     

    -Stephen

     

    Wednesday, June 01, 2011 4:07 AM
  • Hi VanEsch,

    If anything is unclear, please provide us a feedback.

     

    Best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, June 02, 2011 4:54 AM
    Moderator
  • Hi Sheldon and Stephen,

    Thanks for the suggestion Stephen but I couldn't get it to work. I'm still looking for a solution.

    -Steve

    Thursday, June 02, 2011 3:41 PM
  • Reading over my post i see that i was a little unclear that you need to override the OnActivated method on all the windows in your app for this to work.

    I will try and build and post a helper class that will be a cleaner implementation for you.

    Thursday, June 02, 2011 4:51 PM
  • Here is the Helper class along with an implementation, i should mention that on further testing the user can still move other windows but they cannot do anything in them and all windows of the application will always be behind the dialog. In order to prevent the window title bar selection from moving the window you will probably need to get into some interop calls and handlers using user32.dll. You should be able to extend what is provided here if you need to.

     

    <Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication4="clr-namespace:WpfApplication4" Title="MainWindow" Height="350" Width="525">
      <UniformGrid>
        <Button x:Name="btnOpenWindow" Click="btnOpenWindow_Click">Open Window</Button>
        <Button x:Name="btnOpenDialog" Click="btnOpenDialog_Click">Open Dialog</Button>
      </UniformGrid>
    </Window>
    
    

    namespace WpfApplication4 {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
    public MainWindow() {
    InitializeComponent();
    }
    
    private void btnOpenWindow_Click(object sender, RoutedEventArgs e) {
    MainWindow window = new MainWindow();
    window.Show();
    }
    
    private void btnOpenDialog_Click(object sender, RoutedEventArgs e) {
    OpenFileDialog dialog = new OpenFileDialog();
    
    if (ModalDialogHelper.ShowDialog(dialog, Window.GetWindow(this)) == true) {
    // perform logic as usual, dialog will have its properties set
    }
    }
    }
    }
    

    namespace WpfApplication4 {
    public static class ModalDialogHelper {
    private static bool _isDialogOpen;
    
    public static bool IsDialogOpen {
    get { return _isDialogOpen; }
    }
    
    public static bool? ShowDialog(CommonDialog dialog, Window currentWindow) {
    bool? result;
    try {
    Application.Current.MainWindow = currentWindow;
    HookWindowActivatedEvents();
    _isDialogOpen = true;
    result = dialog.ShowDialog();
    }
    finally {
    _isDialogOpen = false;
    UnhookWindowsActivatedEvents();
    }
    
    return result;
    }
    
    private static void UnhookWindowsActivatedEvents() {
    foreach (var obj in Application.Current.Windows) {
    var window = obj as Window;
    if(window != null) {
    window.IsHitTestVisible = true;
    window.Activated -= Window_Activated;
    }
    }
    }
    
    private static void HookWindowActivatedEvents() {
    foreach (var obj in Application.Current.Windows) {
    var window = obj as Window;
    if(window != null) {
    window.IsHitTestVisible = false;
    window.Activated += Window_Activated;
    }
    }
    }
    
    private static void Window_Activated(object sender, EventArgs e) {
    if (IsDialogOpen) {
    Application.Current.MainWindow.Activate();
    }
    }
    }
    }
    

     

    Goodluck and i hope this helps.

    Thursday, June 02, 2011 10:19 PM
  • Hi, does this code need to reset the MainWindow back to its original value after the dialog is closed?
    Monday, July 09, 2012 5:49 PM
  • Hey Dan,

    That is a good observation, during my original testing I did not "need" to reset the MainWindow property back to gain the desired functionality, but its possible there could be some unintended side effects if you did not set it back. I would recommend keeping a local variable of the original value and set it back in the UnhookWindowsActivatedEvents method.

    This also brings up another possible issue opening a modal dialog from within another modal dialog, in this case when you close the second child window the first modal dialog would probably lose its modal functionality, this code could definitely be improved to handle this situation.

    -Stephen



    http://about.me/stephenehlers

    Monday, July 09, 2012 6:05 PM