Как поднять событие в C # - Лучший подход - PullRequest
3 голосов
/ 22 июня 2010

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

В настоящее время в уведомлении используется заголовок события C #, описанный на следующей странице MSDN: http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx

Но я не уверен насчет делегата. Поскольку в описанной мной ситуации поток вызывает делегата. Это потокобезопасный подход для поднятия события?

Лучше ли реализовать сообщения Windows (SendMessage) в C #, а затем реализовать обработчик сообщений в WindowProc.

Цените ваше время на этом.

Ответы [ 3 ]

4 голосов
/ 22 июня 2010

Если вам не требуется очень точный контроль за потоками, вы можете вместо этого использовать BackgroundWorker .Он обрабатывает все межпоточные коммуникации для вас.Вы в основном помещаете свой фоновый код в его обработчик событий DoWork, а затем передаете данные обратно в поток пользовательского интерфейса через события ProgressChanged и RunWorkerCompleted.Ссылка выше содержит полный пример того, как ее использовать.

Но в целом, простое добавление обработчиков событий и создание событий является поточно-ориентированным, если вы следуете некоторым основным рекомендациям.Однако обработчик события будет вызываться в том же потоке, что и код, который вызывает событие.Код обработки событий, возможно, не ожидает вызова в фоновом потоке, поэтому для этого пригодится BackgroundWorker.

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

class MyClass {

    public event EventHandler SomethingHappened;

    protected virtual void OnSomethingHappened(EventArgs e) {
        EventHandler handler = SomethingHappened;
        if (handler != null) {
            handler(this, e);
        }
    }

    public void DoSomething() {
        OnSomethingHappened(EventArgs.Empty);
    }

}
0 голосов
/ 22 июня 2010

Подход делегата не так уж и плох, но проблема в том, что событие вызывает обработчики событий в другом потоке. Это мешает вашему обновлению пользовательского интерфейса, что необходимо сделать в основном потоке. Таким образом, вы можете соответствующим образом использовать InvokeRequired в обработчике событий.

void OnStatusMessage(string s)
{
  // might be coming from a different thread
  if (txtStatus.InvokeRequired)
  {
    this.BeginInvoke(new MethodInvoker(delegate()
    {
      OnStatusMessage(s);
    }));
  }
  else
  {
    StatusBox.Text += s + "\r\n";
    StatusBox.SelectionStart = txtStatus.TextLength;
    StatusBox.ScrollToCaret();
  }
}

Это может не потребоваться при использовании BackgroundWorker, как упоминал Джош. Но это полезно, если вы рассматриваете ThreadPool и WaitCallBack (*) для управления потоками.

Проблема с использованием сообщений Windows заключается в том, что вам нужно знать, в какое окно отправлять сообщения, и несколько подписчиков более болезненны. (Для событий вам просто нужно + = другой обработчик)

  • Я не могу опубликовать гиперссылку для WaitCallBack, потому что у меня еще нет многоканальной родословной.
0 голосов
/ 22 июня 2010

Попробуйте использовать InvokeRequired / Invoke для элементов управления пользовательского интерфейса. Лучше избегать очереди сообщений в необработанных окнах.

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