WinForms Control.BeginInvoke асинхронный обратный вызов - PullRequest
3 голосов
/ 01 марта 2010

У меня есть несколько элементов управления сеткой Janus, которые необходимо заполнить при запуске приложения.

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

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

Пока у меня есть:

public delegate void BindDelegate(IMyGrid grid);

private IAsyncResult InvokeBind(IMyGrid grid)
{
  return ((Control)grid).BeginInvoke(
    new BindDelegate(DoBind), new object[] { grid }
  );
}

private void DoBind(IMyGrid grid)
{
  grid.Bind(); // Expensive operation
}

private void RefreshComplete()
{
  IAsyncResult grid1Asynch = InvokeBind(grid1);
  IAsyncResult grid2Asynch = InvokeBind(grid2);
  IAsyncResult grid3Asynch = InvokeBind(grid2);
  IAsyncResult grid4Asynch = InvokeBind(grid3);
  IAsyncResult grid5Asynch = InvokeBind(grid4);
  IAsyncResult grid6Asynch = InvokeBind(grid5);
}

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

1 Ответ

1 голос
/ 01 марта 2010

Любые прямые манипуляции с Control (экземпляр, который включает все стандартные и расширенные элементы управления WinForms) должны выполняться в потоке, в котором был создан этот элемент управления. Windows GUI не является потокобезопасным, фактически каждое созданное окно (и большинство элементов управления создадут хотя бы одно) имеет привязку к потокам.

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

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

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