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.
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();
You could try to always cancel the close event and set the DialogResult later.
void ConfigTemplatePopup_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (tmpDialogResult != null || DialogResult == true) return;
tmpDialogResult = DialogResult; //this is a field
e.Cancel = true;
var myMessageBox = new WspMessageBox("Are you sure you want to close?", true);
myMessageBox.Closed += (s, e2) =>
{
if (wspMessageBox.DialogResult == true)
{
DialogResult = tmpDialogResult;
}else
{
tmpDialogResult = null;
}
};
myMessageBox.Show();
}
Using async and await in Silverlight 5 you can easy create a static Show method that can be blocking, like
public partial class MyDialog {
MyResultType result;
readonly AutoResetEvent waitHandle;
MyDialog() {
InitializeComponent();
waitHandle = new AutoResetEvent(false);
}
public static Task<MyResultType> Show() {
var dialog = new MyDialog();
dialog.Show();
dialog.Closed += (s, e) => dialog.waitHandle.Set();
return Task<MyResultType>.Factory.StartNew(() => {
dialog.waitHandle.WaitOne(); return dialog.result; });
}
void OkButton_Click(object sender, RoutedEventArgs e) {
result = new MyResultType();
// Initialize result...
Close();
}
}
and call the dialog like
public async void TestDialog() {
var result = await ConfirmBox.Show();
// This code will be performed after the Dialog is closed.
// use result...
}
Task<T>.Factory.StartNew()
is not awaitable. Also, while this answer introduces the async/await pattern into the mix, it does not solve the fundamental problem that you can't block the UI thread without freezing the browser, so this approach offers no real value over and above Keith Mahoney's solution. –
Holley 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.
© 2022 - 2024 — McMap. All rights reserved.