[Silverlight][小技巧]使用Dispatcher使非UI執行緒可存取UI

Silverlight如同WPF與以前的Windows Form程式一般,UI的部分都在單一的執行緒下面執行。在一個WPF的用程式起始的過程中有兩個執行緒

Silverlight如同WPF與以前的Windows Form程式一般,UI的部分都在單一的執行緒下面執行。在一個WPF的用程式起始的過程中有兩個執行緒:

1. UI執行緒

2. 背景執行緒,並協助UI執行緒 (DispatcherObject)

在一個WPF/Silverlight應用程式中絕大部分的UI元件都是繫結到UI執行緒,如果您在非UI 執行緒要變更UI的狀態就會得到UnauthorizedAccessException,如下使用WebRequest向其他的Web要求資料的範例程式:

	   1:  HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/XmlSerializerSilverlightApplication1/XmlSerializerHandler.ashx");
	   2:              request.ContentType = "application/xml";
	   3:              request.Method = "POST";
	   4:   
	   5:              AsyncCallback ac = asyncResult =>
	   6:              {
	   7:                  if (asyncResult.IsCompleted)
	   8:                  {
	   9:                      Stream stream = request.EndGetResponse(asyncResult).GetResponseStream();
	  10:                      StreamReader reader = new StreamReader(stream);
	  11:                      string ResponseStr = reader.ReadToEnd();
	  12:   
	  13:                      List<Employees> mmc = new List<Employees>();
	  14:                      System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(mmc.GetType());
	  15:                      System.Xml.XmlReader XmlReader = XmlReader.Create(new StringReader(ResponseStr));
	  16:                      try
	  17:                      {
	  18:                          mmc = serializer.Deserialize(XmlReader) as List<Employees>;
	  19:                          dataGrid1.ItemsSource = mmc; //會出現UnauthorizedAccessException錯誤
	  20:                      }
	  21:                      catch (Exception ex)
	  22:                      {
	  23:                          throw ex;
	  24:                      }
	  25:                      finally
	  26:                      {
	  27:                          reader.Close();
	  28:                      }
	  29:                  }
	  30:              };
	  31:              request.BeginGetResponse(ac, request);

如下IDE扔回來的錯誤畫面:

image

在WPF/Silverlight 中任何UI 執行緒上的處理都是透過Dispatcher來傳送並處理,因此最簡單的方式就是透過Dispather的BeginInvoke()方法來傳送,上面會變更UI的程式碼也只有一行,所以基本上只要將dataGrid1.ItemsSource = mmc; 與 request.BeginGetResponse(ac, request);這兩行的程式碼的部分放入 Dispatcher.BeginInvoke() 之中,因為在Silverlight 中同樣也沒有同步的Invoke()方法,這個是與WPF其中一個不同的地方。

所以上述的程式碼應該會變成如下:

	   1:  HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost/XmlSerializerSilverlightApplication1/XmlSerializerHandler.ashx");
	   2:              request.ContentType = "application/xml";
	   3:              request.Method = "POST";
	   4:   
	   5:              AsyncCallback ac = asyncResult =>
	   6:              {
	   7:                  if (asyncResult.IsCompleted)
	   8:                  {
	   9:                      Stream stream = request.EndGetResponse(asyncResult).GetResponseStream();
	  10:                      StreamReader reader = new StreamReader(stream);
	  11:                      string ResponseStr = reader.ReadToEnd();
	  12:   
	  13:                      List<Employees> mmc = new List<Employees>();
	  14:                      System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(mmc.GetType());
	  15:                      System.Xml.XmlReader XmlReader = XmlReader.Create(new StringReader(ResponseStr));
	  16:                      try
	  17:                      {
	  18:                          mmc = serializer.Deserialize(XmlReader) as List<Employees>;
	  19:   
	  20:                          this.Dispatcher.BeginInvoke(delegate()
	  21:                              {
	  22:                                  dataGrid1.ItemsSource = mmc;
	  23:                              }
	  24:                          );
	  25:                      }
	  26:                      catch (Exception ex)
	  27:                      {
	  28:                          throw ex;
	  29:                      }
	  30:                      finally
	  31:                      {
	  32:                          reader.Close();
	  33:                      }
	  34:                  }
	  35:              };
	  36:              this.Dispatcher.BeginInvoke(delegate()
	  37:                          {
	  38:                              request.BeginGetResponse(ac, request);
	  39:                          });

 

 

程式中紅色部分即是增加的部分,因為在Silverlight 中也只有非同步的BeginInvoke() 可以使用,它所接受的便是一個delegate的委派,因此直接將非同步的起始點,也就是request.BeginGetResponse(ac, request); 放入BeginInvoke() 即可。同樣的dataGrid1.ItemsSource = mmc;也是相同方式,這是會實際更動UI執行緒的程式碼。此動作會告知UI 執行緒,直接插入UI執行緒的駐列中,表示還有一件UI工作要處理。因此程式可以正常的執行了。

image

一個執行緒的技巧,希望對使用到的朋友有幫助 :D

謝謝各位!


 

簽名:

學習是一趟奇妙的旅程

這當中,有辛苦、有心酸、也有成果。有時也會有瓶頸。要能夠繼續勇往直前就必須保有一顆最熱誠的心。

軟體開發之路(FB 社團)https://www.facebook.com/groups/361804473860062/

Gelis 程式設計訓練營(粉絲團)https://www.facebook.com/gelis.dev.learning/


 

如果文章對您有用,幫我點一下讚,或是點一下『我要推薦,這會讓我更有動力的為各位讀者撰寫下一篇文章。

非常謝謝各位的支持與愛護,小弟在此位各位說聲謝謝!!! ^_^