2010-08-06 84 views
12

對C#比較新,並且想嘗試與它一起使用某些第三方Web服務API。UnauthorizedAccessException:Silverlight應用程序(XAML/C#)中的無效跨線程訪問

這裏是XAML代碼

<Grid x:Name="ContentGrid" Grid.Row="1"> 
     <StackPanel> 
      <Button Content="Load Data" Click="Button_Click" /> 
      <TextBlock x:Name="TwitterPost" Text="Here I am"/> 
     </StackPanel> 
    </Grid> 

,這裏是C#代碼

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://api.twitter.com/1/users/show/keykoo.xml"); 
     request.Method = "GET"; 

     request.BeginGetResponse(new AsyncCallback(twitterCallback), request); 
    } 

    private void twitterCallback(IAsyncResult result) 
    { 
     HttpWebRequest request = (HttpWebRequest)result.AsyncState; 
     HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 
     TextReader reader = new StreamReader(response.GetResponseStream()); 
     string strResponse = reader.ReadToEnd(); 

     Console.WriteLine("I am done here"); 
     TwitterPost.Text = "hello there"; 
    } 

我猜,這是由回調上比一個單獨的線程執行造成的事實UI?在C#中處理這些類型的交互的正常流程是什麼?

謝謝。

+0

謝謝大家的回覆。 – PolandSpring 2010-08-09 17:06:08

+0

另一種方法是使用this.Dispatcher 但這個鏈接對你很有幫助。 http://humrahimcs.wordpress.com/wp-admin/post.php?post=420&action=edit&message=6&postpost=v2 – DoNetDeveloper 2012-02-24 10:12:32

+0

你爲什麼不接受Steve Willcock的回答? – 2012-09-01 15:04:53

回答

2

另一種方法是使用this.Dispatcher.CheckAccess()函數。它與WPF中的相同,但它不會顯示在您的智能感知中,因此您可能沒有看到它。你所做的是檢查你是否可以訪問UI線程,如果你不是,你可以在UI線程上遞歸調用

private void twitterCallback(IAsyncResult result) 
{ 
    HttpWebRequest request = (HttpWebRequest)result.AsyncState; 
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 
    TextReader reader = new StreamReader(response.GetResponseStream()); 
    string strResponse = reader.ReadToEnd(); 

    Console.WriteLine("I am done here"); 
    ////TwitterPost.Text = "hello there"; 
    postMyMessage(TwitterPost.Text); 
} 

private void postMyMessage(string text) 
{ 
    if (this.Dispatcher.CheckAccess()) 
     TwitterPost.Text = text; 
    else 
     this.Dispatcher.BeginInvoke(new Action<string>(postMyMessage), text); 
} 

這只是一個很簡單的例子,並能得到難以管理,一旦你有以上幾個控件的更多。對於一些WPF/Silverlight的東西,我已經使用了一個通用函數,它也需要更新UI控件以及更新本身,這樣我就沒有這些函數中的每個控件可能需要更新後臺線程的結果。

29

通過CheckAccess調用獲得簡單跨線程訪問的有用方法是在靜態類中包裝實用程序方法 - 例如,

public static class UIThread 
{ 
    private static readonly Dispatcher Dispatcher; 

    static UIThread() 
    { 
     // Store a reference to the current Dispatcher once per application 
     Dispatcher = Deployment.Current.Dispatcher; 
    } 

    /// <summary> 
    /// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on 
    /// the current thread so it can be safely called without the calling method being aware of which thread it is on. 
    /// </summary> 
    public static void Invoke(Action action) 
    { 
     if (Dispatcher.CheckAccess()) 
      action.Invoke(); 
     else 
      Dispatcher.BeginInvoke(action); 
    } 
} 

那麼你可以用該更新UI的任何電話,你可能會在後臺線程像這樣:

private void twitterCallback(IAsyncResult result) 
{ 
     HttpWebRequest request = (HttpWebRequest)result.AsyncState; 
     HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 
     TextReader reader = new StreamReader(response.GetResponseStream()); 
     string strResponse = reader.ReadToEnd(); 

     UIThread.Invoke(() => TwitterPost.Text = "hello there"); 
} 

這種方式,你不必知道你是否是一個背景線程與否,它避免了向每個控件添加方法以檢查此操作的開銷。

+0

這對Windows Phone 7非常有用。很棒的解決方案。 – scottbates22 2010-11-19 20:38:12

+0

太棒了!正是我需要的。 – 2012-09-01 14:58:38