简体   繁体   中英

How do I determine if a WPF window is modal?

What's the easiest way to figure out if a window is opened modally or not?

CLARIFICATION:

I open a window calling

myWindow.ShowDialog();

I have a footer with an "OK" & "Cancel" button that I only want to show if the window is opened modally. Now I realize I can set a property by doing this:

myWindow.IsModal = true;
myWindow.ShowDialog();

But I want the window itself to make that determination. I want to check in the Loaded event of the window whether or not it is modal.

UPDATE

The IsModal property doesn't actually exist in a WPF window. It's a property that I have created. ShowDialog() blocks the current thread.

I'm guessing I can determine if the Window is opened via ShowDialog() by checking if the current thread is blocked. How would I go about doing that?

There's a private field _showingAsDialog whenever a WPF Window is a modal dialog. You could get that value via reflection and incorporate it in an extension method:

public static bool IsModal(this Window window)
{
    return (bool)typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(window);
}

The value is set to true when the window is shown as modal (ShowDialog) and set to false once the window closes.

From http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/c95f1acb-5dee-4670-b779-b07b06afafff/

"System.Windows.Interop.ComponentDispatcher.IsThreadModal can tell you if the calling thread is currently running a modal hwnd."

Okay, since my last idea got voted down, I proved it. this works - and I tested it in a new WPF application, so I know it works:

In my main Window's (Window1) Loaded event, I did:

Dim frm As New Window2
frm.ShowDialog()

In my Window2 I shadowed the ShowDialog() method

Private _IsModal As Boolean = False 'This will be changed in the IsModal method

Public Property IsModal() As Boolean
  Get
    Return _IsModal
  End Get
  Set(ByVal value As Boolean)
    _IsModal = value
  End Set
End Property

Public Shadows Sub ShowDialog()
  IsModal = True
  MyBase.ShowDialog()
End Sub

In my Loaded event, I then fired off a message box to make sure that the IsModal property got changed from False to True and it gives me True, so I know IsModal was set. MyBase.ShowDialog() then forces the base class to be loaded as Modal. Shadows allows us to override the default behaviour even though the ShowDialog() method wasn't declared as overridable.

While it doesn't "self determine" it doesn't require you to pass in any boolean value from outside, and doesn't require you to set the IsModal from outside, it sets it inside itself, it's accessible from outside if you so chose to use it that way. It sets the value only if it us loaded using the ShowDialog() method and not if you use the Show() method. I doubt you'll find a much simpler method of doing this.

Here is a converter fragment which is useful for hiding elements when the window is invoked by the ShowDialog method:

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Window window = value as Window;
        if (window != null)
        {               
            var showingAsDialogFieldInfo = typeof(System.Windows.Window).GetField("_showingAsDialog",
                BindingFlags.NonPublic | BindingFlags.Instance);
            if ((bool) showingAsDialogFieldInfo.GetValue(window) == false)
            {
                return Visibility.Visible;
            }
        }
        return Visibility.Hidden;
    }

a modal window will stop processing until it is closed.

This example shows displaying a non-modal window

dim f as myWindow
f.show
someOtherMethod()

In this example, someOtherMethod runs immediately after the window is launched.

This example shows displaying a modal one:

dim f as myWindow
f.showDialog
someOtherMethod()

In this example, someOtherMethod() won't run until the ShowDialog method returns (which means that the modal window has been closed)

EDIT due to clarification: Override the ShowDialog and pass in a boolean.

dim f as MyWindow
f.ShowDialog(true)

then in the window

Public Function Shadows ShowDialog(myVar as boolean) As Boolean
    if myVar then ShowButtons()
    return mybase.ShowDialog()
End Function 

Using UI Automation in Windows, I have come up with something like this:

void Window2_Loaded(object sender, RoutedEventArgs e)
{
    var hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
    var el = AutomationElement.FromHandle(hwnd);

    Object oPattern = null;

    if (el.TryGetCurrentPattern(WindowPattern.Pattern, out oPattern))
    {
        var pattern = oPattern as WindowPattern;

        this.Title = pattern.Current.IsModal.ToString();
    }
}

But this seems not working. There is an IsModal property http://msdn.microsoft.com/en-us/library/system.windows.automation.provider.iwindowprovider.ismodal.aspx there must be a proper way to get AutomationElement for the window and check whether IsModal property of it is true via Automation.

You could also create a new class Dialog that inherits from Window . Create a private variable IsDialog in the Dialog class and override the ShowDialog function using new. Set the IsDialog variable to true when ShowDialog is called:

public class Dialog : Window
{
    private bool IsDialog;

    new public bool? ShowDialog()
    {
        IsDialog = true;
        return base.ShowDialog();
    }
}

Would it be possible to check the window's parent to see if it is disabled? I'm not sure if this can be done via WPF APIs or not, but if nothing else you could get the HWND of the WPF window, get its parent via Win32 P/Invoke (or whatever), and then check to see if it is disabled or not.

Definitely not a clean method, but it seems like it could work.

Window does not allow you to set the value for Window.DialogResult if the window was not opened using ShowDialog(). Hence, you might try to set Window.DialogResult and see if it throws an exception.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM