2010-04-08 4 views
2

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

Вот пример кода, чтобы лучше понять:

class MyClass 
{ 
    // Original object 
    private OriginalObject myObject; 

    // My event 
    public delegate void StatsUpdatedDelegate(object sender, StatsArgs args); 
    public event StatsUpdatedDelegate StatsUpdated; 

    public MyClass() 
    { 
     // Original object event 
     myObject.DoSomeWork(); 
     myObject.AnEvent += new EventHandler(myObject_AnEvent); 
    } 

    // This event is called on another thread while myObject is doing his work 
    private void myObject_AnEvent(object sender, EventArgs e) 
    { 
     // Throw my custom event here 
     StatsArgs args = new StatsArgs(..........); 
     StatsUpdated(this, args); 
    } 
} 

Так что, когда на моих окна образуют я вызываю попробовать обновить управление от события StatsUpdated я получаю перекрестное исключение нити причины его называют по другому нить.

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

Кто-нибудь может мне помочь?

ответ

3

Вы можете ознакомиться с шаблоном InvokeRequired/Invoke.

Прежде чем пытаться обновить некоторый контроль вы проверяете, если требуется Invoke и использовать метод Invoke, который будет заботиться о сортировочной призыв к потоку, который создал этот элемент управления:

Control ctrlToBeModified = // 
if (ctrlToBeModified.InvokeRequired) 
{ 
    Action<Control> del = (Control c) => 
    { 
     // update the control here 
    }; 
    ctrlToBeModified.Invoke(del, ctrlToBeModified); 
} 

UPDATE:

private void myObject_AnEvent(object sender, EventArgs e) 
{ 
    // Throw my custom event here 
    StatsArgs args = new StatsArgs(..........); 
    Control control = // get reference to some control maybe the form or 'this' 
    if (control.InvokeRequired) 
    { 
     Action<Control> del = (Control c) => 
     { 
      // This will invoke the StatsUpdated event on the main GUI thread 
      // and allow it to update the controls 
      StatsUpdated(this, args); 
     }; 
     control.Invoke(del); 
    } 
} 
+0

Invoke является метод, который может быть вызван из контроля, вот что я хочу сделать, это напрямую бросить мое событие на оригинальной нити (из моего класса). Поэтому в моей форме окна мне не нужно заботиться о вызове. Я могу непосредственно сделать что-то вроде «progressbar.value = arg.progress; – Karnalta

+0

В этом случае, когда вы вызываете событие (не указанное в вашем фрагменте), вы проверяете требуемый вызов и вызываете событие внутри делегата, помещенного в метод Invoke –

+0

Я не уверен, что понимаю, вы говорите о моем событии или событии originalObject? – Karnalta

0

Я не уверен, если это так, но если это безопасно, вы можете добавить в свой конструктор формы:

Control.CheckForIllegalCrossThreadCalls= false; 

Это «простой способ», который применяется только в некоторых ограниченных сценариях. В моем случае работает как шарм.

+0

Да, но это также решение, используемое в форме окна, я хотел бы исправить свою проблему внутри своего класса, прежде чем бросать свое пользовательское событие. Поэтому я держу свою DLL максимально простой в использовании в форме Windows. – Karnalta

0

Похоже, вам необходимо изучить классы SynchronizationContext или AsyncOperation.

http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx

+0

Да В настоящее время я читаю эту статью, мне кажется, это то, что я ищу. – Karnalta

+0

Я только что попытался с помощью обоих методов в этой статье, но я все еще получаю ошибку кросс-threading при обновлении моей панели прогресса. Это странно, потому что метод кажется довольно логичным. – Karnalta

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