Как сделать блокировку 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);

В зависимости от того, что должно отображаться в модальном, я динамически добавляю элементы управления в модальный макет. Ясно, что это не элегантное решение, но, по крайней мере, оно работает.