Вызов Invoke / BeginInvoke из потока - PullRequest
4 голосов
/ 01 декабря 2010

У меня есть приложение на C # 2.0 с формой, которая использует класс, содержащий поток.

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

public class Foo
{
    private Control owner_;
    Thread thread_;

    public event EventHandler<EventArgs> FooEvent;

    public Foo(Control owner)
    {
        owner_ = owner;
        thread_ = new Thread(FooThread);
        thread_.Start();
    }

    private void FooThread()
    {
        Thread.Sleep(1000);
        for (;;)
        {
            // Invoke performed in the thread
            owner_.Invoke((EventHandler<EventArgs>)InternalFooEvent, 
                new object[] { this, new EventArgs() });
            Thread.Sleep(10);
        }
    }

    private void InternalFooEvent(object sender, EventArgs e)
    {
        EventHandler<EventArgs> evt = FooEvent;
        if (evt != null)
            evt(sender, e);
    }
}

public partial class Form1 : Form
{
    private Foo foo_;

    public Form1()
    {
        InitializeComponent();

        foo_ = new Foo(this);
        foo_.FooEvent += OnFooEvent;
    }

    private void OnFooEvent(object sender, EventArgs e)
    {
        // does not need to call InvokeRequired/BeginInvoke() 
        label_.Text = "hello";
    }
}

Это явно противоречит методу, используемому API-интерфейсами Microsoft, использующими фоновые потоки, такие как System.Timers.Timer.и System.Io.Ports.SerialPort.Что-то не так с этим методом?Это опасно в некотором роде?

Спасибо, PaulH


Редактировать: также, что, если форма не подписалась на событие сразу?Будет ли это забивать очередь сообщений формы событиями, в которых форма не интересовалась?

1 Ответ

3 голосов
/ 01 декабря 2010

Это потокобезопасный вызов, метод будет обработан в потоке формы.

В этом нет ничего плохого, если смотреть на это с концептуальной точки зрения.

Хотя таймеры более элегантны для таких задач. Однако может случиться так, что таймер с интервалом 10 мс замедляет графический интерфейс, поэтому, вероятно, был использован Invoke.

Вам не нужен вызов InvokeRequired, поскольку ясно, что элемент управления находится в другом потоке. Кроме того, BeginInvoke необходимо вызывать только тогда, когда вы хотите вызвать метод асинхронно, что, очевидно, здесь не так.

Относительно вашего редактирования: Нет, очередь сообщений не будет засорена. Событие не будет запущено, если обработчик не зарегистрирован. Посмотрите еще раз на ваш код;)

...