.NET события, темы и сообщения - PullRequest
4 голосов
/ 30 октября 2010

Я понимаю, что обработчик событий выполняется в любом потоке, который вызвал событие. Я также понимаю необходимость обновления элементов управления формы только из потока, который создал элементы управления. Я предполагаю, что поток UI - тот, который создал форму для цели этого вопроса.

Если событие является результатом опубликованного сообщения, такого как сообщение рисования, разве обработчик не отделен от исходного потока? Если это так, то любой поток может вызывать операции аннулирования, и результирующее рисование всегда будет происходить в потоке пользовательского интерфейса, поскольку он обрабатывает сообщения формы.

Вот как это выглядит в моей голове около 2:00 утра с длинной пустой миской для закусок рядом со мной. Пожалуйста, уточните и исправьте, чтобы у меня было правильное понимание механизмов работы.

Ответы [ 3 ]

5 голосов
/ 30 октября 2010

MSDN:

Вызов метода Invalidate не приводит к синхронному рисованию;чтобы вызвать синхронную рисование, вызовите метод Update после вызова метода Invalidate.

Итак, Invalidate можно вызывать из любого потока, а Update - только из потока пользовательского интерфейса.В любом случае, чтобы быть на 100% уверенным, что вы не используете недопустимые вызовы между потоками, установите для свойства Control :: CheckForIllegalCrossThreadCalls значение true в начале программы.Это приводит к немедленному сбою любого недействительного вызова, вам не нужно угадывать.

1 голос
/ 30 октября 2010

Во-первых, см. Ответ Алекса.

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

Я говорю здесь очень широко;но учтите, что любой код может внутренне упорядочить вещи в потоке пользовательского интерфейса, вызвав Control.Invoke () или эквивалентный ему код.

В вашем собственном коде приложения, конечно, вы должны обязательно это сделать.Но я просто предполагаю, что если вы найдете где-нибудь код, который, кажется, нарушает этот принцип, то, вероятно, Invoke () где-то для вас.

0 голосов
/ 30 октября 2010

Даже если технически это возможно сделать, у вас будут проблемы. Код для 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).

Короче говоря. Вы не должны вызывать это из другого потока. Вы должны вызывать все методы, которые взаимодействуют с Control (так же Form) через Invoke или BeginInvoke.

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