views:

117

answers:

4

Update: I guess, what I need is to understand what is the "correct", "supported" way to show a dialog before application start in WPF.

Here's the code:

    public partial class App : Application
    {
        [STAThread]
        public static void Main()
        {
            var app = new App();
            app.InitializeComponent();

            new DialogWindow().ShowDialog();

            app.Run( new MainWindow() );
        }
    }

The DialogWindow shows up as expected.
But after closing it, the application exits immediately. MainWindow doesn't show up at all!

I have done some debugging and traced the problem to this:

  1. When the dialog is created, it becomes app's MainWindow, since there is no MainWindow at the moment.
  2. Therefore, closing the dialog causes the application to post ShutdownCallback on the dispatcher queue.
  3. However, the dispatcher doesn't run long enough to execute the callback.
  4. Therefore, once app.Run is called subsequently, the first thing on the queue is ShutdownCallback, which, naturally, causes the app to close immediately.

Given this analysis, there is an obvious workaround: create MainWindow right after App, thus making it app's MainWindow, which would prevent DialogWindow from causing application closure.

However, here is what bothers me.

First, this looks like a dirty hack to me. I mean, there is no explicit reason for creating windows in this order, and I have only found this through some debugging. This can't be the supported way.

Second, this is clearly a bug. I mean, if creating a second window after shutdown wasn't supported explicitly, it should've thrown some InvalidOperationException, right?

Thirdly, not only is this a bug, but it looks like a very naive one, something like a multithreading beginner would create.

All this leads me to believe that maybe I don't get something fundamental here? Maybe I don't make sense at all? Maybe it all should be done in some different fashion?

Here's some background:
The application has to do some bootstrapping on startup. Check this and that, setup exception handlers, logging - you know, the usual stuff. In this process, it may become necessary to ask the user for some help - which is what the dialog is for.

I absolutely don't want to put all that in some kind of state machine that executes on MainWindow.IsVisibleChanged or something like that. I would like to keep it really simple, short and straightforward - the way bootstrap code is supposed to be, so that it's easy to spot bugs with a naked eye.

A: 

I think , when you use show dialogue so main window for the application is the dialogue one and when you close that dialogue ,there is no active window so your app is closing down. And you already figured that out.

So, I think you have answers for this question.

Normally these dialogue are part Of a window means a window shows a dialogue.

But your point is correct.

I need to know what is your business problem that you are showing a dialogue first?

saurabh
For the business problem description, see the last two paragraphs.
Fyodor Soikin
A: 

I've not seen this problem specifically, but does my answer to this question help at all?

Groky
No, I don't think so. If I call `App.Run()` without argument, it will block, won't it? And then I won't be able to continue running my bootstrap code. And besides, if I start the dispatcher pump before the bootstrap is finished, it pretty much defeats the purpose.
Fyodor Soikin
I've also updated the post with a more precise phrasing of what I need after all.
Fyodor Soikin
+1  A: 

It does seem buggy.

I usually don't put anything in Main(), I let the no-arg app.Run() get called and call everything I need in the OnStartup method, but this wouldn't change the behaviour you're seeing.

Whenever I need to show something before my main application window is ready to be displayed, such as gathering input or showing a splash screen, I do it on a second thread.

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);

    // show splash
    var thread = new Thread(() =>
    {
        Dispatcher.CurrentDispatcher.BeginInvoke
            ((Action)(() => new MySplashWindow().Show()));
        Dispatcher.Run();
    }
    thread.SetApartmentState(ApartmentState.STA);
    thread.IsBackground = true;
    thread.Start();

    // run configuration steps

    // instantiate and show main window
}

Obviously, if you're calling ShowDialog() on a second thread, you'll need to make sure you get an answer before showing the main window. It does have the advantage that you can run other bootstrapping tasks while waiting for user input on a particular part; it really depends on how sequential your various tasks are.

Maybe that helps in your case; maybe not -- just a thought.

Jay
Well, I already do have a working workaround. What I would like to know is how it is "supposed" to be done. Somehow, I doubt dialogs are supposed to be shown from a different thread. That being said, this is a good idea, thanks.
Fyodor Soikin
@Fyodor I think you are supposed to use an explicit shutdownmode: http://msdn.microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx
Jay
A: 

If you set the Application.ShutdownMode to OnExplicitShutdown can you avoid putting the ShutdownCallback on the dispatcher queue and keep doing whatever you want without regard to windows? I have not tested this but it seems like a potential solution as well as using the Application.MainWindow property which can be changed on the fly.

jomtois