WPF线程 - 有人能解释一下这里发生了什么吗?

时间:2009-01-20 00:29:22

标签: wpf multithreading

免责声明:以下代码不是我在实际应用程序中使用的代码。我偶然发现了这个问题,想知道引擎盖下发生了什么。

让我们假设出于某种疯狂的原因,我们有以下代码......

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 个答案:

答案 0 :(得分:1)

我认为在WPF中,它会尝试将所有回调放在它们来自的线程上。这被称为线程的“亲和力”。

答案 1 :(得分:1)

我是WPF(以及WinForms,Win32以及我曾经使用过的任何其他UI库),您只能从创建它的同一个线程中访问UI对象。

此外,在任何GUI Windows程序中,您都有一个消息循环和消息调度,而在控制台应用程序中则没有。

所以它看起来像是

  1. WebClient检测到它正在GUI应用程序中运行,并尝试通过在激活它的同一线程中引发事件来提供帮助。
    1. WebClient在内部使用消息调度,仅在控制台应用程序中回退到工作线程。

答案 2 :(得分:1)

好的,我用Reflector进行了一些反编译,我已经弄清楚了引擎盖下发生了什么。 Web客户端使用SynchronizationContext类来处理在原始线程上放置回调。我不熟悉SynchronizationContext类,但这里有一篇非常好的文章...

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