Вопрос

У меня есть следующий код, чтобы отправить запрос на 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);
}

И ошибка

Поперечная операция не действительна: Control 'TXTSearch', доступ к потоку, кроме потока, на котором он был создан.

Это было полезно?

Решение

Вы звоните BeginInvoke Таким образом, ваш делегат вызывается в потоке резьбы. Вы не можете получить доступ к пользовательскому интерфейсу из этого потока потока; Вам нужно позвонить Invoke или же BeginInvoke На управлении, чтобы затем использовать результаты в потоке пользовательского интерфейса. Например, используя анонимный метод:

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

Или с использованием выражения лямбды и с отдельной локальной переменной только для ясности:

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

С использованием Invoke Сделает блок вызова, пока поток пользовательского интерфейса не вызовет делегата; BeginInvoke не блокирует.

РЕДАКТИРОВАТЬ: Если проблема в том, что result.TotalResults это бит, который занимает много времени, сделайте это все еще на фоновом потоке:

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

Другие советы

Вместо Delegate.BeginInvoke Вы можете рассмотреть возможность использования Фоновый работник. Анкет Фонообразователь поднимает RunWorkerCompleted событие после того, как он закончил, что Бежит в потоке пользовательского интерфейса, поэтому вы можете обновить свой пользовательский интерфейс там.

Поскольку доступ к элементам управления формами не защищен по своей природе, отладчик предупреждает, что вы нарушаете правила, получая его из другого потока. Вместо этого вы можете Invoke управление непосредственно, чтобы получить желаемые результаты. Есть отличный, всеобъемлющий учебник Microsoft о том, как это сделать здесь.

Сообщение об ошибке говорит вам, в чем проблема. Вы не можете безопасно манипулировать элементами управления пользовательским интерфейсом на потоке, отличной от того, который создал элемент управления; отладчик предназначен для того, чтобы поймать это (см. MSDN для получения подробной информации).

Итак, вам нужно позвонить BeginInvoke На управлении, чтобы он выполнялся в потоке пользовательского интерфейса, или вам нужно настроить некоторый механизм связи между вызываемым потоком и потоком пользовательского интерфейса. Очевидно, первое может быть достигнуто просто с TextBox.BeginInvoke:

txtSearch.BeginInvoke(sd, new object[] { keyword, orderBy, SearchCompleted });
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top