2010-08-06 18 views
12

Relativamente nuovo a C# e voleva provare a giocare con alcune API di servizi Web di terze parti.UnauthorizedAccessException: accesso cross-thread non valido nell'applicazione Silverlight (XAML/C#)

Ecco il codice 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> 

e qui è il codice 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"; 
    } 

Sto indovinando che questo è causato dal fatto che il callback viene eseguito su un thread separato rispetto alla UI? Qual è il flusso normale per gestire questi tipi di interazioni in C#?

Grazie.

+0

Grazie a tutti per le vostre risposte. – PolandSpring

+0

Un altro modo per fare ciò è usare il this.Dispatcher ma questo link è molto utile per te. http://humrahimcs.wordpress.com/wp-admin/post.php?post=420&action=edit&message=6&postpost=v2 – DoNetDeveloper

+0

Perché non accetti la risposta di Steve Willcock? –

risposta

2

Un altro modo per fare ciò è utilizzare la funzione this.Dispatcher.CheckAccess(). È lo stesso di quello che ottieni in WPF ma non compare nella tua intelligenza quindi potresti non averlo visto. Quello che fai è controllare se hai accesso al thread dell'interfaccia utente e, se non lo fai, ricorri in modo ricorsivo sul thread dell'interfaccia utente.

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

Questo è solo un esempio molto semplice e può diventare ingestibile quando si dispone di più di alcuni controlli. Per alcune cose di WPF/Silverlight ho usato una funzione generica che tiene anche il controllo dell'interfaccia utente per essere aggiornato così come l'aggiornamento stesso, in questo modo non ho una di queste funzioni per ogni controllo sulla pagina che potrebbe richiedere l'aggiornamento da i risultati di un thread in background.

29

Un modo utile per ottenere un accesso incrociato semplice con la chiamata CheckAccess è di racchiudere un metodo di utilità in una classe statica, ad es.

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

allora si può avvolgere tutte le chiamate che aggiornano l'interfaccia utente in cui si può essere su un thread in background in questo modo:

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"); 
} 

In questo modo non c'è bisogno di sapere se siete su uno sfondo thread o no ed evita il sovraccarico di aggiungere metodi a ogni controllo per verificarlo.

+0

Funziona alla grande per Windows Phone 7. ottima soluzione. – scottbates22

+0

Fantastico! Proprio quello di cui avevo bisogno. –

Problemi correlati