无法从异步方法完成回调更新Silverlight UI

无法从异步方法完成回调更新Silverlight UI

问题描述:

我继承了一些通过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

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