Обновление интерфейса из другого потока - PullRequest
1 голос
/ 07 апреля 2009

Я знаю, что этот вопрос задавался ранее, но я чувствую, что он не был задан правильно.

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

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

Пример, который я видел на сайте MSDN, предполагал, что у источника будет источник.

Я знаю, как получить прогресс (который является процентным значением), прикрепляя его к событиям, но как мне вернуть это значение в пользовательский интерфейс?

Ответы [ 4 ]

2 голосов
/ 07 апреля 2009

Следующий ответ основан на моих интуитивных чувствах и фактически не проводил тест со сторонними библиотеками.

  • Вызывайте свой сторонний код lib, как обычно, в простом фоновом (не BackGroundWorker) потоке.
  • Присоединение событий компонентов библиотеки к обычным обработчикам событий в вашем коде (предназначено для обновления пользовательского интерфейса).
  • В коде события обработчик должен выглядеть так:

    private void EventHandler(object sender, DirtyEventArgs e)
    {
        if (myControl.InvokeRequired)
            myControl.Invoke(new MethodInvoker(MethodToUpdateUI), e);
        else
            MethodToUpdateUI(e);
    }
    
    private void MethodToUpdateUI(object obj) 
    {
        // Update UI
    }
    
1 голос
/ 07 апреля 2009

Присоединитесь к событиям прогресса в стороннем компоненте и наберите ReportProgress на BackgroundWorker. Для обновления пользовательского интерфейса подключите событие BackgroundWorker.ProgressChanged.

0 голосов
/ 07 апреля 2009

Аналогичное обсуждение на этом Q . Если вы не можете или не хотите использовать BackgroundWorker по какой-либо причине, вы можете использовать свой собственный поток и маршалировать события из него обратно в свой поток пользовательского интерфейса.

private void Initialise() {      
    MyLibClass myLibClass = new MyLibClass();
    myLibClass.SomeEvent += SomeEventHandler;
    ThreadPool.QueueUserWorkItem(myLibClass.StartLongTask);
}


private void SomeEventHandler(EventArgs e) {     
   if (this.Dispatcher.Thread != Thread.CurrentThread) { 
      this.Dispatcher.Invoke(delegate { DoStuffOnUIThread(e); });
   }
   else {        
       DoStuffOnUIThread(e);     
   }
}
0 голосов
/ 07 апреля 2009

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

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

Использование таймера (Windows.Forms.Timer), который будет проверять эту очередь каждый раз x и в случае появления новых событий, может обновить пользовательский интерфейс.

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

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