Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF
Tip/Trick

Custom ShowDialog() method for WPF

Rate me:
Please Sign up or sign in to vote.
3.20/5 (5 votes)
29 Apr 2011CPOL3 min read 43.6K   4   2
Custom ShowDialog() method for WPF
In one of my articles, I have considered DispatcherFrame. I tried to look in-depth of DispatcherFrame, showed some IL sources of .NET and tried to explain what it is.

While reading MSDN about the threading model, I saw a section, which said that PushFrame() can be used to create something like WPF dialog windows. That window takes control after calling ShowDialog() and doesn’t return control to the parent window until closed. So, I wondered, how to create such window?
During this article, you will also learn how to get full control on process of showing and hiding custom modal windows and how to control blocking and unblocking of another windows.

Custom ShowModal()

For the first, I tried to open a new window in a separate thread. It works! But when I clicked on suspended parent window 5-10 times, that window gets “Not responded”. Not good!

I really wondered how to block parent window, but prevent it from suspension. I thought about how to use DispatcherFrame here. Obviously, if the main thread is blocked, then the parent window will be also blocked, because of blocked dispatcher. So, there is no way to use PushFrame in such a solution.

After that, I decided to use Reflector to see how ShowDialog() is implemented in WPF. So, what do I see? WINAPI is used there to block each window in the current thread.

[SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("user32.dll", EntryPoint="EnableWindow", CharSet=CharSet.Auto)] 
public static extern bool IntEnableWindowNoThrow(HandleRef hWnd, bool enable); 


This method is called for each window with enable = false. As you guessed, the solution comes closer. To implement my own ShowModal(), I should perform following steps:

  • Block parent window
  • Add event handler on modal closed and unblock parent window inside this handler
  • Show modal window and call PushFrame()

That’s it!

[DllImport("user32")]
internal static extern bool EnableWindow(IntPtr hwnd, bool bEnable);

public void ShowModal()
{
    IntPtr handle = (new WindowInteropHelper(Application.Current.MainWindow)).Handle;
    EnableWindow(handle, false);

    DispatcherFrame frame = new DispatcherFrame();

    this.Closed += delegate
    {
        EnableWindow(handle, true);
        frame.Continue = false;
    };

    Show();
    Dispatcher.PushFrame(frame);
}


First, we define extern method which uses WINAPI to enable/disable windows. Exactly that method is used in WPF ShowDialog(). Then we blocks window, show modal and push new DispatcherFrame.

Why do we have to use PushFrame() here? The answer is to prevent returning from ShowModal() method. When a new frame is pushed, the main loop is suspended and a new loop starts. This new loop processes system messages and execution point in main loop doesn’t go forward. When modal closes, DispatcherFrame.Continue = false, and this frame is exited. And after that, the application is back to normal flow.
This approach has no obvious advantages compared to ShowDialog() method. Dialog behaviour is totally the same.

But there is one benefit that can be very useful in some cases. The benefit provided by this method is full control on blocking and unblocking windows from modal window. Say, what if you needed to block only 2 of 4 active windows? Or unblock window while dialog is shown? It could be problematic with classic ShowDialog() method. Of course, you can use WinAPI, but this is not so obvious as with custom ShowModal() method.

Also, you can put windows blocking and unblocking command anywhere. Just put PushFrame() and frame.Continue = false, to places of code, where you want to stop or continue default application flow, and you will get it. It can be useful if you want to continue main frame flow without closing of modal window or otherwise don't continue it after closing.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Luxoft
Russian Federation Russian Federation
My developers career starts in 1995, when my father bought my first PC and gave my book "QBasic".
Than it was Pascal, Delphi, C++ Builder...But when I began to work with .Net in 2008, I understand, that this technology is exactly what I need Smile | :)

For now, I am a Senior .Net developer at Luxoft.

P.S. Right now I am extremly looking for a legal job offer from USA.

Comments and Discussions

 
Generalhow to define a return value? Pin
jang08310-Jun-11 10:04
jang08310-Jun-11 10:04 
GeneralRe: how to define a return value? Pin
Renat Khabibulin30-Jun-11 1:07
Renat Khabibulin30-Jun-11 1:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.