2014-12-18 3 views
0

Есть ли способ запустить код в потоке пользовательского интерфейса при вызове его вне его? Я знаю, что в основном это требует использования control.Invoke или control.BeginInvoke. Моя проблема в том, что у меня нет доступа к элементам пользовательского интерфейса, чтобы использовать эти методы.Как запустить код из потока пользовательского интерфейса в C#

Моя ситуация такова:

  1. UI - DataGridView с DataTable набора, как это DataSource
  2. нить (BackgroundWorker), написанный за пределами MainForm UI, что обновления (добавляет строки) DataTable упоминалось выше

У меня были проблемы с моим приложением, поэтому я написал простое приложение с указанными выше элементами, чтобы проверить, как это работает (или, вернее, почему это не так), и я обнаружил, что:

  1. Когда я обновляю DataTable в потоке BackgroundWorker, DataGridview не видит этого (возможно, все события запускаются из другого потока), даже вызов DGV.Refresh() не работает (он обновляет DGV, но иногда DGV сломается и не показывает ничего или только 1 строку), только заставляя DGV освежающие с изменением размеров, прокрутка и т.д. заставляет DGV отображать данные из DataTable
  2. , когда я могу запустить Invoke, все работает отлично, ничего не сказать

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

+0

Отделите источник данных и управление от пользовательского интерфейса и фона. Таким образом, любой из 2 может получить доступ к общему управлению. Посмотрите на IoC для идей. Вы также можете использовать async/await, но из-за его звука у вас вообще нет доступа к коду пользовательского интерфейса? Итак, вы манипулируете сторонней программой? – user3036342

+1

Как насчет использования метода ReportProgress и события ProgressChanged для фактического обновления вашего пользовательского интерфейса? Они сделаны именно для этой цели. См. Http://msdn.microsoft.com/en-us/library/System.ComponentModel.BackgroundWorker%28v=vs.110%29.aspx для примера. –

+0

Это может помочь вам: [WinForms многопоточный сценарий привязки данных, лучшая практика?] (Http://stackoverflow.com/questions/602735/winforms-multi-threaded-databinding-scenario-best-practice) – Larry

ответ

4

вы можете использовать Application.OpenForms этим:

public void DoSomething(string s) 
    { 
     var form = System.Windows.Forms.Application.OpenForms[0]; 
     if (form.InvokeRequired) 
     { 
      Action<string> m = DoSomething; 
      form.Invoke(m, s); 
      return; 
     } 

     //do something 
    } 
+0

Работа как шарм^_^конечно, может быть, есть лучшие решения, но это все, что мне нужно сейчас, спасибо –

1

Вы всегда можете использовать Application.OpenForms[0], чтобы получить ссылку на главную форму и, таким образом, есть что-то называть Invoke дальше.

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

Затем, когда рабочий закончен (событие RunWorkerCompleted вызывается в контексте потока пользовательского интерфейса), я бы объединил записи результатов в таблицу связанных данных. Это обеспечивает четкое разделение кода, который обновляет пользовательский интерфейс и код, который может даже работать без звука.

Смежные вопросы