.NET事件,线程和消息

时间:2010-10-30 05:49:46

标签: .net multithreading events

我理解事件处理程序在调用事件的任何线程上执行。我进一步理解只需要从创建控件的线程更新表单控件。我假设UI线程是为此问题创建表单的那个。

如果事件是发布消息的结果,例如绘制消息,那么处理程序是否与原始线程分离?如果这是真的,那么任何线程都可以调用失效操作,并且结果绘制将始终出现在UI线程上,因为它是处理表单消息的那个。

这就是它在凌晨2点左右在我脑海中映射出来的方式,我身边有一个长长的空小吃碗。请澄清并纠正,以便我能够正确理解工作中的机制。

3 个答案:

答案 0 :(得分:5)

MSDN:

调用Invalidate方法不会强制执行同步绘制;要强制执行同步绘制,请在调用Invalidate方法后调用Update方法。

因此,可以从任何线程调用Invalidate,并且仅从UI线程调用。在任何情况下,要100%确定不使用无效的跨线程调用,请在程序开头将Control :: CheckForIllegalCrossThreadCalls属性设置为true。这会导致任何无效调用立即失败,您无需猜测。

答案 1 :(得分:1)

首先,请参阅亚历克斯的答案。

其次,请注意,仅仅因为你做了一些事情导致消息泵中的某些内容结束,从而导致UI线程上的事件,并不绝对意味着启动操作必须在同一个线程上发生。

我在这里讲得非常广泛;但请注意,任何代码都可以通过调用Control.Invoke()或等效函数在内部封送到UI线程。

在您自己的应用程序代码中,您必须确保这样做。但我只是建议如果你在某个地方找到似乎违反了这个原则的代码,那么可能会在某处为你调用Invoke()。

答案 2 :(得分:0)

即使技术上可能会这样做,但你会遇到麻烦。 Invalidate的代码如下:

public void Invalidate(bool invalidateChildren) {
    if (IsHandleCreated) {
        if (invalidateChildren) {
            SafeNativeMethods.RedrawWindow(new HandleRef(window, Handle),
                                            null, NativeMethods.NullHandleRef,
                                            NativeMethods.RDW_INVALIDATE |
                                            NativeMethods.RDW_ERASE |
                                            NativeMethods.RDW_ALLCHILDREN);
        }
        else {
            // It's safe to invoke InvalidateRect from a separate thread.
            using (new MultithreadSafeCallScope())
            {
                SafeNativeMethods.InvalidateRect(new HandleRef(window, Handle),
                                                null,
                                                (controlStyle & ControlStyles.Opaque) != ControlStyles.Opaque);
            }
        }

        NotifyInvalidate(this.ClientRectangle);
    }
}

这里有一些问题:

  1. 如果在Form检查完成后处理IsHandleCreated,则句柄将消失;

  2. 将在调用线程上调用调用NotifyInvalidate来触发OnInvalidated事件的Invalidated。注册到该事件的处理程序可能不会期望从其他线程调用它;

  3. 尽管这表明可以从单独的线程调用InvalidateRect,但它并未说明RedrawWindow是否可以。因此,问题就变成了您是拨打Invalidate(false)(或Invalidate(),这是否映射到false),还是致电Invalidate(true)

  4. 长话短说。你不应该从另一个线程调用它。您应该通过ControlForm调用与Invoke(以及BeginInvoke)互动的所有方法。