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





Я думаю, что в WPF он пытается поместить все обратные вызовы в поток, из которого они пришли. Это называется «сродством» нити.
I מ WPF (а также в WinForms, Win32 и любой другой библиотеке пользовательского интерфейса, с которой я когда-либо работал) вы можете получить доступ к объекту пользовательского интерфейса только из того же потока, который его создал.
Кроме того, в любой программе Windows с графическим интерфейсом пользователя у вас есть цикл сообщений и отправка сообщений, а в консольном приложении - нет.
Так что, похоже, либо
или же
In WPF you can only access a UI object from the same thread that created it. Это неверно для фиксируемых элементов пользовательского интерфейса.
Хорошо, я немного декомпилировал с помощью Reflector и разобрался, что происходит под капотами. Веб-клиент использует класс SynchronizationContext для обработки обратных вызовов в исходный поток. Я не был знаком с классом SynchronizationContext, но здесь есть очень хорошая статья об этом ...
Вы делаете эту загрузку в своей ветке пользовательского интерфейса?