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

本文关键字:回调 更新 Silverlight UI 异步方法 | 更新日期: 2023-09-27 18:24:50

我继承了一些代码,这些代码通过WCF服务查询数据库,然后在完成后使用回调。我试图在回调中添加一些代码,以便在处理数据时更新UI。我发现我无法在回调期间更新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,直到(显然)整个回调完成。这篇文章:

哪个线程在silverlight WCF调用上调用已完成的事件处理程序?

建议回调正在主UI线程上运行,因此不需要BeginInvoke调用。即使我在上面的代码中添加了各种延迟,它仍然不起作用。这可能吗?有更好的方法吗?

(这是一个后续问题:Silverlight中的多个异步UI更新)

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

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();