免责声明:以下代码不是我在实际应用程序中使用的代码。我偶然发现了这个问题,想知道引擎盖下发生了什么。
让我们假设出于某种疯狂的原因,我们有以下代码......
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的主线程上?
答案 0 :(得分:1)
我认为在WPF中,它会尝试将所有回调放在它们来自的线程上。这被称为线程的“亲和力”。
答案 1 :(得分:1)
我是WPF(以及WinForms,Win32以及我曾经使用过的任何其他UI库),您只能从创建它的同一个线程中访问UI对象。
此外,在任何GUI Windows程序中,您都有一个消息循环和消息调度,而在控制台应用程序中则没有。
所以它看起来像是
或
答案 2 :(得分:1)
好的,我用Reflector进行了一些反编译,我已经弄清楚了引擎盖下发生了什么。 Web客户端使用SynchronizationContext类来处理在原始线程上放置回调。我不熟悉SynchronizationContext类,但这里有一篇非常好的文章...