Question

Je le code suivant pour envoyer une requête à youtube et envoyer le résultat total à une zone de texte. Si je d'alerte pour le résultat, il est OK, mais je ne peux pas affecter le résultat à une zone de texte. S'il vous plaît me expliquer pourquoi?

private void SearchVideo(string keyword)
{
    string orderBy = "";
    switch (cboSortBy.SelectedIndex)
    {
        case 1: orderBy = "published"; break;
        case 2: orderBy = "viewCount"; break;
        case 3: orderBy = "rating"; break;
        default: orderBy = "relevance"; break;
    }
    SearchDelegate sd = Search;
    sd.BeginInvoke(keyword, orderBy, SearchCompleted, sd);
}

private void SearchCompleted(IAsyncResult ar)
{
    if (null == ar) return;
    SearchDelegate sd = ar.AsyncState as SearchDelegate;
    Feed<Video> result = sd.EndInvoke(ar);
    txtSearch.Text = result.TotalResults.ToString();
}

private Feed<Video> Search(string keyword, string orderBy)
{
    YouTubeQuery query = new YouTubeQuery(YouTubeQuery.DefaultVideoUri);
    query.OrderBy = orderBy;
    query.Query = keyword;
    query.SafeSearch = YouTubeQuery.SafeSearchValues.None;
    return GetRequest().Get<Video>(query);
}

Et l'erreur

  

opération de la Croix-fil non valide:   Contrôle « txtSearch » accessible à partir d'un   fil autre que le fil était   créé.

Était-ce utile?

La solution

Vous appelez BeginInvoke de sorte que votre délégué est invoquée sur un fil fil piscine. Vous ne pouvez pas accéder à l'interface de ce fil fil piscine; vous devez appeler Invoke ou BeginInvoke sur le contrôle d'utiliser ensuite les résultats sur le thread d'interface utilisateur. Par exemple, en utilisant une méthode anonyme:

txtSearch.BeginInvoke((MethodInvoker) delegate() 
    { txtSearch.Text = result.TotalResults.ToString(); }
);

Ou en utilisant une expression lambda, et avec une variable locale séparée juste pour la clarté:

MethodInvoker action= () => { txtSearch.Text = result.TotalResults.ToString();};
txtSearch.BeginInvoke(action);

Utilisation Invoke fera le bloc de thread appelant jusqu'à ce que le thread d'interface utilisateur a invoqué le délégué; BeginInvoke est non bloquant.

EDIT: Si le problème est que result.TotalResults est le bit qui prend beaucoup de temps, faire encore peu sur le fil de fond:

string text = result.TotalResults.ToString();
txtSearch.BeginInvoke((MethodInvoker) delegate() { txtSearch.Text = text; });

Autres conseils

Au lieu de Delegate.BeginInvoke vous pouvez envisager d'utiliser un BackgroundWorker . Un BackgroundWorker déclenche l'événement RunWorkerCompleted après qu'il ait fini, qui fonctionne dans le thread d'interface utilisateur , de sorte que vous pouvez mettre à jour l'interface utilisateur il.

Parce que l'accès aux commandes de formulaires ne sont pas thread-safe en soi, le débogueur vous avertit que vous enfreignez les règles en y accédant à partir d'un autre thread. Au lieu de cela, vous pouvez Invoke le contrôle directement pour obtenir les résultats que vous voulez. Il y a un grand, tutoriel Microsoft complète de la façon de le faire

Le message d'erreur vous dit exactement ce que le problème est. Vous ne pouvez pas manipuler en toute sécurité les contrôles de l'interface utilisateur sur un thread différent de celui qui a créé le contrôle; le débogueur est conçu pour attraper ce (voir MSDN pour plus de détails).

Alors, soit vous devez appeler BeginInvoke sur le contrôle afin qu'il soit exécuté sur le thread d'interface utilisateur, ou vous avez besoin de mettre en place un mécanisme de communication entre le fil et invoqué le fil de l'interface utilisateur. Il est évident que l'ancien peut être accompli simplement avec TextBox.BeginInvoke :

txtSearch.BeginInvoke(sd, new object[] { keyword, orderBy, SearchCompleted });
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top