Как сделать блокировку ChildWindow
ChildWindow - это модальное окно, но оно не блокируется. Есть ли способ заблокировать его? В основном я хочу, чтобы метод ShowDialog() вызывал ChildWindow.Show(), но затем не возвращался, пока пользователь не закрыл ChildWindow. Я попытался использовать Monitor.Enter() для блокировки после ChildWindow.Show(), но ChildWindow никогда не отображался и браузер просто зависал. У кого-нибудь есть идеи?
Ответы
Ответ 1
Я не верю, что он поддерживает это поведение. Вы можете голосовать за него в CodePlex. В зависимости от того, что вы хотите, вы можете посмотреть некоторые из обходных решений Тима Хейера здесь или использовать другой настраиваемый элемент управления, например Silverlight Modal Control (на CodePlex).
Ответ 2
Вы не можете делать то, что вы пытаетесь сделать в Silverlight. Любые изменения, которые вы вносите в пользовательский интерфейс, будут выполняться в потоке пользовательского интерфейса. Если вы блокируете поток пользовательского интерфейса, пользователь не может взаимодействовать с браузером, поэтому нет никаких действий, которые они могли бы предпринять, чтобы разблокировать поток.
Если вы действительно хотите создать диалоговое окно блокировки, единственный способ сделать это - не-UI-поток. Например. вы можете создать метод, который выглядит примерно так:
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();
}
Этот метод отобразит диалоговое окно и не вернется, пока диалоговое окно не будет закрыто. Но этот метод можно вызывать только из не-UI-потока. Вызов его из UI-потока приведет к тупиковой ситуации (поскольку UI-поток ожидает события, которое может срабатывать только в пользовательском потоке).
В качестве альтернативы вам следует подумать о том, чтобы сделать вашу логику асинхронной, а не принуждать ее к синхронному.
Ответ 3
Если вы хотите выполнить какое-либо действие по закрытию вашего дочернего окна, используйте следующий код. Скрыть нежелательные элементы управления перед вызовом и показать при закрытии дочернего окна, просто:)
ChildWindow cw = new ChildWindow();
cw.Closed += new EventHandler(cw_Closed);
cw.Show();
Ответ 4
Вы можете попытаться всегда отменить событие закрытия и позже установить DialogResult.
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();
}
Ответ 5
Используя асинхронный и ожидающий в Silverlight 5, вы можете легко создать статический метод Show, который может блокироваться, например
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();
}
}
и вызовите диалог, например
public async void TestDialog() {
var result = await ConfirmBox.Show();
// This code will be performed after the Dialog is closed.
// use result...
}
Ответ 6
Я взломал при создании "блокирующего" модального диалога, создав собственный элемент управления, который имеет вертикальное и горизонтальное выравнивание как растягивание, а затем добавит его как дочерний элемент макета текущего элемента управления.
например.
<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Rectangle Fill="LightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.3" />
</Grid>
а затем в пользовательском элементе управления
Utilities.UITools.MessageBox x = new Utilities.UITools.MessageBox();
x.SetError(e.Result);
this.LayoutRoot.Children.Add(x);
В зависимости от того, что должно отображаться в модальном, я динамически добавляю элементы управления в модальный макет. Ясно, что это не элегантное решение, но, по крайней мере, оно работает.