The ChildWindow is a modal window, but it does not block. Is there any way to make it blocking? I basically want a ShowDialog() method that will call ChildWindow.Show() but then not return until the user has closed the ChildWindow. I tried using Monitor.Enter() to block after ChildWindow.Show(), but the ChildWindow never rendered and the browser just hung. Anyone have any ideas?
I don't believe it supports that behavior. You can vote for it on CodePlex. Depending on what you want, you might either look at some of Tim Heuer's workarounds here, or use a different custom control, like the Silverlight Modal Control (on CodePlex).
You can't do what you are trying to do in Silverlight. Any changes you make to the UI will run on the UI thread. If you block the UI thread, the user can't interact with the browser, so there is no action that they could take to unblock the thread.
If you really want to create a blocking dialog window, the only way to do that is from a non-UI-thread. E.g. you could create a method that looks something like:
private void ShowModalDialog()
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
Dispatcher.BeginInvoke(() =>
{
ChildWindow cw = new ChildWindow();
cw.Content = "Modal Dialog";
cw.Closed += (s, e) => waitHandle.Set();
cw.Show();
});
waitHandle.WaitOne();
}
This method will show a dialog window and won't return until the dialog window is closed. But this method can only be called from a non-UI-thread. Calling it from the UI-thread will cause a deadlock (since the UI-thread is waiting for an event that can only fire on the UI-thread).
Alternatively, you should consider making your logic async rather than forcing it to be synchronous.
I've tried everything and I never found a solution. I was trying to make my own MessageBox. I even tried async but it always locked up. I gave up after reading that Tim Heuer saying it wasn't possible to have true Modal.
I hacked away at creating a "blocking" modal dialog, by having a custom control that has a vertical- and horizontal alignment as stretch, and then add that as a child of the layout of the current control.
e.g.
<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Rectangle Fill="LightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.3" />
</Grid>
and then in the custom control
Utilities.UITools.MessageBox x = new Utilities.UITools.MessageBox();
x.SetError(e.Result);
this.LayoutRoot.Children.Add(x);
Depending on what has to be displayed in the modal, I dynamically add controls to the modal layout. Clearly, not an elegant solution, but at least it works.
Hi, Jeff,
In solution,
private void ShowModalDialog()
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
Dispatcher.BeginInvoke(() =>
{
ChildWindow cw = new ChildWindow();
cw.Content = "Modal Dialog";
cw.Closed += (s, e) => waitHandle.Set();
cw.Show();
});
waitHandle.WaitOne();
}
How can we retrive cw inside Dispatcher.BeginInvoke()?
Because after "waitHandle.WaitOne();", we might need to check the cw.DialogResult for the next operation.
If you want to perform some action on your child window close, use the following code. Hide unwanted controls before invoke and show on close of the child window, simple :)
ChildWindow cw = new ChildWindow();
cw.Closed += new EventHandler(cw_Closed);
cw.Show();