2009-03-05 2 views
0

Хорошо, пожалуйста, не обращайте внимания на то, что было раньше. Я больше не получаю ошибки, поэтому мне кажется, что проблема заключается в получении диаграммы для обновления при изменении значений, которым привязана карта.Control.Refresh() По темам

// Оставься здесь ниже

Привет всем. У меня есть приложение WinForms, которое имеет панель, panel1. Фоновый поток создает некоторые другие элементы управления, которые затем добавляются в panel1 как так

panel1.Controls.AddRange(myArrayOfControls); 

Это прекрасно работает, и я могу видеть мои элементы управления добавляются. Но когда новые данные поступают в другой поток, я обновляю значения в родительских объектах элементов управления, а затем должен Refresh(), чтобы обновить отображение новыми значениями. Вызов Refresh() в любом контексте, поток, в который входят данные или объекты, которые получают обновленные данные, вызывает исключение InvalidOperation, поскольку Invoke требуется. Я попытался использовать Invoke в объектах модели, а также поток, в котором данные поступают, и не может пошатнуть ошибку.

Если у кого-то есть руководство, я очень благодарен.

ОБНОВЛЕНИЕ: вот немного больше информации. Я не думал, что это потребует, но я ошибся. :)

У меня есть объект класса MyObject. Этот класс MyObject создается в потоке, называемом topologyThread. Данные поступают в dataThread. В экземплярах MyObject есть переменная экземпляра Panel, и у Panel есть дочерние элементы управления, включая два диаграммы из пространства имен System.Windows.Forms.DataVisualization.Charting. Таким образом, по мере поступления данных в dataThread, я обновляю соответствующие значения данных в объектах MyObject, а затем обновляю диаграммы для отображения обновленных данных.

Я знаю, что данные обрабатываются штрафом. В моем классе MyObject я регистрирую новые значения в Console в setter для свойства и вижу, как появляются новые значения.

ответ

6

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

Лучший способ сделать это состоит в использовании

theControl.Invoke(new MethodInvoker(MyUpdateMethod)); 

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

0

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

public static class ControlInvokeExtensions 
{ 
    public static void InvokeOnHostThread(Control host, MethodInvoker method) 
    { 
     if (IsHandleCreated) 
      Invoke(new EventHandler(delegate { method(); })); 
     else 
      method(); 
    } 
} 

теперь вы можете назвать это так

panel1.InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls)); 

или если вы в форме:

InvokeOnHostThread(() => panel1.Controls.AddRange(myArrayOfControls)); 
1

JaredPar является довольно хороший ответ. Я хотел бы добавить к нему немного о том, почему ваш код работает.

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

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

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

Бог, я хотел бы прокомментировать. :)

+1

+1, теперь вы на 10 повторений ближе к возможности комментировать. :) –

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