Silverlight Подтвердите диалог, чтобы приостановить поток
Я пытаюсь сделать диалог подтверждения, используя Silverlight ChildWindow
объект.
В идеале я бы хотел, чтобы это работало как MessageBox.Show()
где все приложение останавливается до тех пор, пока не будет получен ввод от пользователя.
Например:
for (int i = 0; i < 5; i++)
{
if (i==3 && MessageBox.Show("Exit early?",
"Iterator", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
break;
}
}
Остановит итерацию на 3, если пользователь нажмет OK...
Однако, если бы я сделал что-то вроде:
ChildWindow confirm = new ChildWindow();
confirm.Title = "Iterator";
confirm.HasCloseButton = false;
Grid container = new Grid();
Button closeBtn = new Button();
closeBtn.Content = "Exit early";
closeBtn.Click += delegate { confirm.DialogResult = true; confirm.Close(); };
container.Children.Add(closeBtn);
Button continueBtn = new Button();
continueBtn.Content = "Continue!";
continueBtn.Click += delegate { confirm.DialogResult = false; confirm.Close(); };
container.Children.Add(continueBtn);
confirm.Content = container;
for(int i=0;i<5;i++) {
if (i==3) {
confirm.Show();
if (confirm.DialogResult.HasResult && (bool)confirm.DialogResult) {
break;
}
}
}
Это явно не будет работать, так как поток не останавливается... confirm.DialogResult.HasResult
будет ложным, и цикл будет продолжаться после 3.
Мне просто интересно, как я мог сделать это правильно. Silverlight является однопоточным, поэтому я не могу просто уложить нить в спящий режим, а затем разбудить его, когда я буду готов, поэтому мне просто интересно, есть ли что-нибудь еще, что люди могли бы порекомендовать?
Я подумал о том, чтобы поменять логику - то есть передать действия, которые я хочу выполнить, событиям Да / Нет, но в моем конкретном случае это не совсем сработало бы.
Заранее спасибо!
3 ответа
Я не думаю, что вы сможете заблокировать свой код в цикле сообщений, как вы можете с WinForms " ShowDialog
,
Однако вы можете неправильно использовать итераторы для достижения того же эффекта:
interface IAction { void Execute(Action callback); }
public static void ExecAction(IEnumerator<IAction> enumerator) {
if (enumerator.MoveNext())
enumerator.Current.Execute(() => ExecAction(enumerator));
}
class DialogAction : ChildWindow, IAction {
void IAction.Execute(Action callback) {
//Show the window, then call callback when it's closed
}
}
IEnumerator<IAction> YourMethod() {
...
var confirm = new DialogAction();
yield return confirm;
if (confirm.DialogResult.HasResult && (bool)confirm.DialogResult)
yield break;
...
}
Чтобы использовать эту систему, вы должны написать ExecAction(YourMethod());
, Обратите внимание, что это будет полублокирующий вызов, и я его вообще не проверял.
C# 5 новый async
функции работают точно так же (на самом деле, первоначальные версии async
код компилятора был в значительной степени основан на существующей реализации итератора), но с более приятной синтаксической поддержкой.
Вы можете легко достичь этого спокойствия с RX Framework:
var continued = Observable.FromEvent<RoutedEventArgs>(continueBtn, "Click");
var iter = new Subject<int>();
var ask = iter.Where(i => i == 3).Do(_ => confirm.Show());
iter.Where(i => i != 3 && i < 10)
.Merge(ask.Zip(continued, (i, _) => i))
.Do(i => Debug.WriteLine("Do something for iteration {0}", i))
.Select(i => i + 1)
.Subscribe(iter);
iter.OnNext(0);
Решение легко масштабируется для любого правила, определяющего, когда показывать диалог. Например, предположим, что мы хотим заблокировать итерацию и запрашивать подтверждение пользователя каждые 3 итерации. Все, что вам нужно сделать, это заменить условие i == 3
с i % 3 == 0
(а также i != 3
с i % 3 != 0
).
Проверьте этот проект http://silverlightmsgbox.codeplex.com/. Он представляет собой простую, но презентабельную реализацию нескольких полезных окон сообщений, таких как подтверждение, ошибка, информация, ввод пользователя и т. Д., И может быть полезен для вас. Удачи.