В Windows Forms существует два золотых правила потоков:
- Не трогайте никакие свойства или методы элемента управления (кроме тех, которые явно указаны как допустимые) из любого потока, кроме того, который создал «дескриптор» элемента управления (обычно это только один поток пользовательского интерфейса)
- Не блокируйте поток пользовательского интерфейса в течение значительного промежутка времени, иначе приложение не будет отвечать на запросы
Чтобы взаимодействовать с пользовательским интерфейсом из другого потока, необходимо «маршалировать» вызов потока пользовательского интерфейса, используя делегат и вызывая Control.Invoke
/ BeginInvoke
. Вы можете проверить, нужно ли вам звонить Invoke
, используя свойство InvokeRequired
, но в наши дни я лично все равно склонен делать это в любом случае - не нужно много штрафов за вызов, когда вам не нужно к.
Лямбда-выражения в C # 3 (или анонимные методы в C # 2) также делают это намного приятнее.
Например, вы можете использовать:
cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear()));
Все скобки немного мешают, так что вы можете добавить метод расширения, подобный этому, если вы используете C # 3:
public static void Invoke(this Control control, MethodInvoker action)
{
control.Invoke(action);
}
Тогда вы могли бы сделать:
cbFly.Invoke(() => cbFly.Items.Clear());
что намного проще. Обычно вы можете избежать использования MethodInvoker
, захватив все переменные, к которым вам нужен доступ в делегате.
См. мой учебник потоков или Джо Албахари для более подробной информации.
В качестве вторичного вопроса я вижу, что вы используете Thread.Abort
- фактически в своем собственном потоке, несмотря на то, что после него есть другие вызовы. Зачем? Отмена любого потока , отличного , кроме вашего, является вызовом типа «только для экстренных случаев» (за которым обычно следует загрузка приложения в любом случае), и я не вижу причин прерывать текущий поток, когда он еще работа, которую предстоит сделать потом ...