1

YouTubeにクエリを送信し、合計結果をテキストボックスに送信する次のコードがあります。結果を警告するだけなら問題ありませんが、結果をテキストボックスに割り当てることはできません。理由を教えてください。

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

そしてエラー

クロススレッド操作が無効です: コントロール 'txtSearch' は、それが作成されたスレッド以外のスレッドからアクセスされました。

4

4 に答える 4

4

BeginInvokeデリゲートがスレッドプールスレッドで呼び出されているように呼び出しています。そのスレッドプール スレッドから UI にアクセスすることはできません。UI スレッドで結果を使用するには、コントロールでInvokeまたはを呼び出す必要があります。BeginInvokeたとえば、匿名メソッドを使用すると、次のようになります。

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

または、ラムダ式を使用し、明確にするために別のローカル変数を使用します。

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

UsingInvokeは、UI スレッドがデリゲートを呼び出すまで、呼び出しスレッドをブロックします。BeginInvokeノンブロッキングです。

編集: 問題がresult.TotalResults長い時間がかかるビットである場合は、バックグラウンド スレッドでそのビットを実行します。

string text = result.TotalResults.ToString();
txtSearch.BeginInvoke((MethodInvoker) delegate() { txtSearch.Text = text; });
于 2010-01-17T14:17:17.250 に答える
1

代わりに、 BackgroundWorkerDelegate.BeginInvokeの使用を検討してください。BackgroundWorkerは終了後にイベントを発生させ、UI スレッドで実行されるため、そこでユーザー インターフェイスを更新できます。RunWorkerCompleted

于 2010-01-17T14:22:05.397 に答える
0

フォーム コントロールへのアクセスは本質的にスレッド セーフではないため、デバッガーは、別のスレッドからアクセスすることで規則に違反していることを警告しています。代わりにInvoke、コントロールを直接使用して、必要な結果を得ることができます。これを行う方法に関する優れた包括的な Microsoft チュートリアルがここにあります。

于 2010-01-17T14:20:42.127 に答える
0

エラー メッセージは、問題の内容を正確に示しています。コントロールを作成したスレッドとは異なるスレッドで UI コントロールを安全に操作することはできません。デバッガーはこれをキャッチするように設計されています (詳細については、 MSDNを参照してください)。

そのため、UI スレッドで実行されるようにコントロールを呼び出すかBeginInvoke、呼び出されたスレッドと UI スレッド間の通信メカニズムをセットアップする必要があります。明らかに、前者は次のように簡単に実行できますTextBox.BeginInvoke

txtSearch.BeginInvoke(sd, new object[] { keyword, orderBy, SearchCompleted });
于 2010-01-17T14:21:25.023 に答える