WPF Threading - Может кто-нибудь объяснить, что здесь происходит? - PullRequest
1 голос
/ 20 января 2009

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Следующий код не то, что я бы когда-либо использовал в реальном приложении. Я наткнулся на эту проблему и хотел бы знать, что происходит под капотами.

Давайте предположим, что по какой-то безумной причине у нас был следующий код ...

using (System.Net.WebClient webClient = new System.Net.WebClient())
{
    bool done = false;
    webClient.UploadFileCompleted += (s, e) => done = true;

    string uploadUri = "ftp://www.notarealurl.com/";
    string file = @"temp.txt";

    webClient.UploadFileAsync(
        new Uri("ftp://www.notarealurl.com/"), "temp.txt");

    while (!done)
    {
        System.Threading.Thread.Sleep(100);
    }
}

Этот код работает, как и ожидалось, в простом консольном приложении. Однако переместите его в приложение WPF, и оно никогда не выйдет из цикла while. Это проходило через меня некоторое время, пока мне не пришло в голову, что это может быть связано с тем, что события отбрасываются в насосе сообщений и поэтому не обрабатываются. Чтобы проверить это, я изменил цикл while, как этот ...

while (!done)
{
    System.Threading.Thread.Sleep(100);

    // Processes all messages currently in the message queue
    Dispatcher.Invoke(
        DispatcherPriority.Background, new ThreadStart(delegate { }));
}

Конечно, это исправило. Итак, к вопросу ...

Что здесь происходит? Когда я запускаю этот код в консольном приложении, обработчик событий выполняется в рабочем потоке. Почему / как он помещается в основной поток в WPF?

Ответы [ 3 ]

1 голос
/ 20 января 2009

В WPF (а также в WinForms, Win32 и любой другой библиотеке пользовательского интерфейса, с которой я когда-либо работал) доступ к объекту пользовательского интерфейса возможен только из того же потока, в котором он был создан.

Кроме того, в любой программе Windows с графическим интерфейсом пользователя есть цикл обработки сообщений и диспетчеризация сообщений, в консольном приложении - нет.

Так что похоже на

  1. WebClient обнаруживает, что работает в приложении с графическим интерфейсом, и пытается помочь, вызывая события в том же потоке, который его активировал.

или

  1. WebClient использует внутреннюю диспетчеризацию сообщений и использует рабочие потоки только в консольных приложениях.
1 голос
/ 20 января 2009

Хорошо, я сделал небольшую декомпиляцию с помощью Reflector и выяснил, что происходит под капотами. Веб-клиент использует класс SynchronizationContext для обработки обратных вызовов в исходном потоке. Я не был знаком с классом SynchronizationContext, но здесь есть очень хорошая статья об этом ...

http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx

1 голос
/ 20 января 2009

Я думаю, что в WPF он пытается поместить все обратные вызовы в поток, из которого они пришли. Это называется "сродством" потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...