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;您需要调用InvokeBeginInvoke在控件上然后使用 UI 线程上的结果。例如,使用匿名方法:

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

或者使用 lambda 表达式,并使用单独的局部变量,只是为了清楚起见:

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

而不是Delegate.BeginInvoke您可以考虑使用BackgroundWorkerRunWorkerCompletedBackgroundWorker在完成后引发事件,该事件在 UI 线程中运行,因此您可以在那里更新您的用户界面。

于 2010-01-17T14:22:05.397 回答
0

因为对 Forms 控件的访问本质上不是线程安全的,所以调试器会警告您从不同的线程访问它违反了规则。相反,您可以Invoke直接通过控件来获得您想要的结果。这里有一个很棒的、全面的 Microsoft 教程来说明如何做到这一点

于 2010-01-17T14:20:42.127 回答
0

错误消息准确地告诉您问题所在。您不能在与创建控件的线程不同的线程上安全地操作 UI 控件;调试器旨在捕获这一点(有关详细信息,请参阅MSDN)。

因此,您要么需要调用BeginInvoke控件以使其在 UI 线程上执行,要么需要在被调用线程和 UI 线程之间建立某种通信机制。显然前者可以简单地完成TextBox.BeginInvoke

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