2010-01-21 116 views
6

我正在嘗試使用Silverlight的ChildWindow對象進行確認對話框。Silverlight確認對話框暫停線程

理想情況下,我希望它能像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是單線程的,所以我不能只讓線程進入睡眠狀態,然後在準備就緒時將其喚醒,所以我只是想知道是否還有其他人可以推薦的東西?

我已經考慮了顛倒邏輯 - 即將想要發生的動作傳遞給Yes/No事件,但在我的具體情況下,這不起作用。

在此先感謝!

回答

11

我不認爲你可以像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編譯器代碼的初始版本主要基於現有的迭代器實現),但具有更好的語法支持。

+1

這真是天才! 我會給你一個鏡頭,看看它的工作效果如何... – AlishahNovin 2010-01-21 22:53:09

+0

它可以很容易地被採用在後臺線程中執行枚舉器,使一個非常簡單的多線程UI工作流。 – SLaks 2010-01-21 22:55:29

+0

+1。小問題:你是不是指'YourMethod'中的'yield return confirm'? – 2011-03-17 01:11:22

1

您可以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 == 0(和i != 3i % 3 != 0)替換條件i == 3

0

看看這個項目http://silverlightmsgbox.codeplex.com/。它提供了幾個有用的消息框,即確認,錯誤,信息,用戶輸入等,並且可能對你有所幫助。祝你好運。

+0

這與問題無關 - 他要求阻止呼叫。 – SLaks 2011-03-17 01:13:18