2009-04-02 2 views
7

Когда я пытаюсь изменить свойство UI (в частности, включить) мой поток бросает System.Threading.ThreadAbortExceptionДоступа к UI в потоке

Как получить доступ к UI в теме.

ответ

15

Вы можете использовать BackgroundWorker, а затем изменить пользовательский интерфейс, как это:

control.Invoke((MethodInvoker)delegate { 
    control.Enabled = true; 
}); 
+0

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

+0

Вы выигрываете за использование наименьшего количества текста и за отображение наиболее яркого примера/объяснения. Kudos – 2009-04-03 07:39:03

+0

Спасибо, самый простой способ заглянуть в мое время. – Tirth

1

Как насчет использования фона BackgroundWorker для Win Form вместо ручной синхронизации синхронизации aad?

3

Я предполагаю, что мы говорим о WinForms здесь? У вас должен быть один поток, управляющий этим - поток, который создал данный элемент управления. Если вы хотите сделать это из другого потока, который вы можете обнаружить с помощью Control.InvokeRequired, тогда вы должны использовать метод Control.Invoke для его сортировки на правильный поток. Google это свойство и метод (соответственно) для некоторых общих шаблонов при этом.

+0

Вы можете безопасно использовать BeginInvoke(), а также в большинстве случаев, если вы не хотите маршировать любое заброшенное исключение обратно в вызывающий поток. – Quibblesome

+0

'InvokeRequired/BeginInvoke' слишком многословен, IMO. –

1

Используйте SynchronizationContext для перенаправления вызовов в поток пользовательского интерфейса, если вы хотите изменить пользовательский интерфейс, пока поток, отличный от UI, все еще работает. В противном случае используйте BackgroundWorker.

1
void button1_Click(object sender, EventArgs e) { 
    var thread = new Thread(ParalelMethod); 
    thread.Start("hello world"); 
} 
void ParalelMethod(object arg) { 
    if (this.InvokeRequired) { 
     Action<object> dlg = ParalelMethod; 
     this.Invoke(dlg, arg); 
    } 
    else { 
     this.button1.Text = arg.ToString(); 
    } 
} 
6

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

public static class FormExtensions 
{ 
    public static void InvokeEx<T>(this T @this, Action<T> action) where T : Form 
    { 
    if (@this.InvokeRequired) 
    { 
     @this.Invoke(action, @this); 
    } 
    else 
    { 
     action(@this); 
    } 
    } 
} 

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

this.InvokeEx(f => f.label1.Text = "Hello"); 
Смежные вопросы