2012-02-17 65 views
0

我繼承了一些通過WCF服務查詢數據庫的代碼,然後在完成時使用回調。我正在嘗試向該回調中添加一些代碼,以便在數據處理時更新UI。我發現,我不能讓UI到回調過程中更新:直到(顯然)整個回調完成無法從異步方法完成回調更新Silverlight UI

client.GetDataAsync(); 
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted); 

void GetDataCompleted(object sender, GetDataCompletedEventArgs e) 
{ 
    // Loop through the data 
    // ... 
    textBlock1.Text= "test1"; 
    Dispatcher.BeginInvoke(() => textBlock1.Text= "test2"); 
    var thread = new Thread(() => 
    { 
    // textBlock1.Text= "test3"; (this throws a cross-thread access exception) 
    Dispatcher.BeginInvoke(() => 
    { 
     textBlock1.Text= "test4"; 
    }); 
    } 
    thread.Start(); 
    // ... 
    Debug.WriteLine("done"); 
} 

這一切都不更新UI。這個帖子:

What thread calls the completed event handler on silverlight WCF calls?

表明回調的主UI線程上運行,這樣的BeginInvoke的調用應該是不必要的。即使我在上面的代碼中添加了各種延遲,它仍然不起作用。這可能嗎?有一個更好的方法嗎?

(這是一個後續問題是:Multiple asynchronous UI updates in Silverlight

+0

工作(是嗎?一個更好的方法)的Silverlight您正在使用什麼版本?新的Task.Factory.FromAsync工程是一種享受。您擺脫了事件處理程序,代碼變得更加可讀,並且您可以更好地控制事件執行的地點/時間。 – 2012-02-17 04:44:24

回答

1

degorolls是正確的暗示TPL,你的代碼看起來像下面的(除了沒有評論)(另外,異常必須在辦理TPL,所以這可能使它不值得,但我不認爲它應該)。 第一種方法將保持不變,並且是在基於事件的異步編程中,線程安全性得到了處理(即:您總是返回到您調出的同一線程) 我還注意到文本輸出全部正在執行=而不是+ =,但這可能更像是輸入溢出問題 因此,test1和test2會同時打印出來,但是從TPL代碼中吐出的所有東西都應該打印出來。 UI代碼不應該做任何需要太多時間的事情,儘管......只更新UI。那麼,請將此視爲重構的一點嗎? 讓我知道這是否有幫助,或者如果我錯過了你要找的東西。

client.GetDataAsync(); 
client.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(GetDataCompleted); 

void GetDataCompleted(object sender, GetDataCompletedEventArgs e) 
{ 
    // Loop through the data 
    // ... 
    textBlock1.Text= "test1"; 
    //////Dispatcher should not be needed here as this IS on the main UI thread 
    Dispatcher.BeginInvoke(() => textBlock1.Text= "test2"); 
    //////Everything that happens here should NOT be on the main UI thread, thus the cross-thread access exception 
    //////You can do Dispatcher.CheckAccess to determine if you need to invoke or not 
    //////Notice the newCopyOfDataToBeWritten. This is a closure, 
    //////so using the same referenced object will result in errant data as it loops 
    //////Also, doing it this way does not guarantee any order that this will be written out 
    //////This will utilize the parallel fully, but there are ways to force the order 
    var task = Task.Factory.StartNew(()=> 
    { 
     Dispatcher.BeginInvoke(()=>textBlock1.Text += newCopyOfDataToBeWritten) 
    } 
); 
    // ... 
    ///////I assume this is the end of the loop? 
    Debug.WriteLine("done"); 
} 

.... 以下空置向下代碼根據你發佈什麼似乎爲我

var outsideThread = new Thread(()=> 
{   
    for(int i = 0; i < 20; i++) 
      { 
       //This code will show all at once since it is on the main thread, 
       //which is still running 
       //If you want this to display one at a time also, then you need 
       //to use threads and callbacks like below, also 
       Dispatcher.BeginInvoke(()=>{textBlock1.Text += "outer" + i;}); 
       int newI = i; 
       var thread = new Thread(() => 
       { 
        System.Threading.Thread.Sleep(1000 * newI); 
        Dispatcher.BeginInvoke(() => 
        { 
         //This will display as it comes in 

         textBlock1.Text += "inner" + newI; 
        }); 
       }); 
       thread.Start(); 
      } 
}); 
outsideThread.Start(); 
+0

謝謝。我收集這不是SL4的選項,我知道我堅持...我更關心這一點爲什麼我的代碼不起作用!無論什麼問題對SL編程來說都是至關重要的。 – jordanpg 2012-02-18 00:28:33

+0

你是對的,我忘記了只有SL5是TPL原生。然而,我剛剛運行了一些代碼,基本上就是你說的,它對我很有用...我將更新以上,以便它顯示更清潔 – 2012-02-18 04:09:41

+0

它在主線程中工作,但它在回調(GetDataCompleted)中不起作用...看到我原來的代碼的前兩行。 – jordanpg 2012-02-20 21:54:12