tags:

views:

477

answers:

6

Is there a way to start off showing a dialog modally, but then instead of hiding it, to keep it visible while changing it to a non-modal dialog?

I want to show a dialog, blocking the method that shows the dialog. Then when the user clicks the 'Finish' button on the dialog I want:

  • The dialog to remain visible.
  • Control to return to the method that showed the dialog.

I've achieved this result by running the dialog on a separate STA thread, and using an event to block the main UI thread until 'Finish' is pressed, but there's a catch to this method: you can click on the close button of the 'main' window while the dialog is visible, and the main window closes when the dialog is hidden.

Update

Thanks for the responses so far. Sorry - it looks like I got the balance wrong between too much background and not enough.

The form is effectively a modal 'wizard' dialog - it appears, sits in front of the main app modally, and then is hidden. So as far as the user's concerned there's no non-standard weirdness going on. The only difference is that the dialog is driven from a series of callbacks from the UI thread, so I don't think making it truly modal (via a call to ShowDialog) for its lifetime would work. The first callback must show the dialog, and then block while the user sets their preferences via the dialog UI. After that, the dialog stays visible and displays a progress bar page while various other callbacks are made from the UI thread. Eventually the form is hidden. The user isn't interacting with the main window while the form is up. As far as they're concerned, it should appear to be 100% modal wrt the main UI thread.

(The form is a dialog for a Visual Studio wizard - these are driven from a series of callbacks on the UI thread). An alternative would be to show the dialog, hide it, immediately show a topmost 'progress' form instead and then hide that, but I think showing a single dialog is more seamless an experience for the user.

Again - sorry for the confusion!

+6  A: 

Perhaps you want to rethink your interaction model? How are you going to explain this to your users? They have an internalized model of how computer programs work, and you better have a very good reason to break that. They know about modal dialogs, they know about non-modal dialogs, they know about inspectors. Choose one, and apply it.

Modal dialogs are made for short-time interaction. They should not block exiting the application. The user is in control of the interaction, the program only provides the minimum of restrictions needed.

[after the explanation, replaced] What's wrong with showing the progress bar in the modal dialog? Start processing once ok is clicked, disabling all buttons, only keeping the cancel button active? If it takes a long time, the user might want to abort the action. Only close the dialog when you're finished processing.

Stephan Eggermont
Hopefully the further explanation helps to clarify the user interaction.
mackenir
It's definitely a modal dialog - it is getting the settings from the user when creating a new project, and then displaying a progress bar while the project is generated.
mackenir
+1  A: 

You could use a modeless dialog then have your main UI check if the user has clicked the Finished button. If the modeless dialog is open but Finished hasn't been clicked then don't respond to any users actions in the main form...

Arnshea
A: 

This is just a terrible idea - it's completely non-standard behavior and you're going to jump through all kinds of hoops to get something working that is just going to horribly confuse your users.

17 of 26
A: 

I'd make it a flyout from the side or bottom of your app that shoves other things out of the way. If it's on top of other stuff that the user might need to see or interact with then it's just gonna annoy them.

jcollum
A: 

Like most of the other answers here stated, you're implement non-standard UI elements that will be confusing to most users.

If the dialog remains visible just to provide read-only access to the data, then why not have dialog window close normally and open a side-bar window in your application with the data from the dialog window?

If the dialog remains visible to allow the users to continue making updates in it, then perhaps, it shouldn't be modal to begin with.

Point is, there's a couple different ways you can accomplish your task without breaking standard UI metaphors.

SergioL
A: 

I found that showing an an invisible modal dialog on the main UI thread during the blocking stage of the interaction works great.

Hidden modal dialog settings (so it's not visible): ShowInTaskBar=false, FormBorderStyle=None, size={0,0}, Opacity=0%, StartupPosition=CenterParent.

The hidden dialog is shown on the UI thread using ShowDialog. The visible dialog is shown on a separate STA thread. The thread is kicked off before calling hiddenDialog.ShowDialog on the main UI thread.

The visible dialog hides hiddenDialog when it wants the initial blocking state to complete. This stops the main UI thread from blocking.

The important bits of code:

void LaunchWizardForm(s)
{
  // Show the wizard on its own thread.
  ThreadStart t = () =>
  {
    _wizard = new WizardForm(s);
    Application.Run(new ApplicationContext(_wizard));
  };
  var thread = new Thread(t);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start();

  // Block this (main UI) thread
  _hiddenForm.ShowDialog();
}

void EndModalEpisode()
{
    _hiddenForm.Invoke((Action) (() => _hiddenForm.Hide()));
}
mackenir
You need to be careful with Opacity, it can fail over remote desktops and some (albeit crap) video cards
johnc