2010-10-18 11 views
7

In meiner Anwendung verwende ich einen Timer, um nach Updates in einem RSS-Feed zu suchen. Wenn neue Elemente gefunden werden, öffne ich einen benutzerdefinierten Dialog, um den Benutzer zu informieren. Wenn ich den Check manuell durchführe, funktioniert alles gut, aber wenn die automatische Überprüfung in den Timern Elapsed event ausgeführt wird, wird das benutzerdefinierte Dialogfeld nicht angezeigt.Aufrufmethode auf dem GUI-Thread von einem Timer-Thread

Zunächst ist dies ein Thema Problem? (Ich gehe davon aus, dass sowohl der manuelle als auch der automatische Test denselben Code verwenden).

Wenn ich die automatische Überprüfung ausführen, muss ich die Methode aufrufen, die die Überprüfung aus dem Ereignishandler Timer Elapsed ausführt?

Gibt es etwas, was ich in meiner benutzerdefinierten Dialogklasse tun muss?

Bearbeiten: Dies ist eine winforms-Anwendung.

Hier ist ein Beispiel dafür, wie der Code ist. (Bitte erwähnen Sie in diesem Codebeispiel keine Syntaxfehler, dies ist nur ein einfaches Beispiel, kein realer Code).

public class MainForm : System.Windows.Forms.Form 
{ 
    //This is the object that does most of the work. 
    ObjectThatDoesWork MyObjectThatDoesWork = new ObjectThatDoesWork(); 
    MyObjectThatDoesWork.NewItemsFound += new NewItemsFoundEventHandler(Found_New_Items); 

    private void Found_New_Items(object sender, System.EventArgs e) 
    { 
     //Display custom dialog to alert user. 
    } 

    //Method that doesn't really exist in my class, 
    // but shows that the main form can call Update for a manual check. 
    private void Button_Click(object sender, System.EventArgs e) 
    { 
     MyObjectThatDoesWork.Update(); 
    } 

    //The rest of MainForm with boring main form stuff 
} 


public class ObjectThatDoesWork 
{ 
    System.Timers.Timer timer; 

    public ObjectThatDoesWork() 
    { 
     timer = new System.Timers.Timer(); 
     timer.Interval = 600000; 
     timer.AutoReset = true; 
     timer.Elapsed += new new System.Timers.ElapsedEventHandler(TimeToWork); 
     timer.Start(); 
    } 

    private void TimeToWork(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     Update(); 
    } 

    public void Update() 
    { 
     //Check for updates and raise an event if new items are found. 
     //The event is consumed by the main form. 
     OnNewItemsFound(this); 
    } 

    public delgate void NewItemsFoundEventHandler(object sender, System.EventArgs e); 
    public event NewItemsFoundEventHandler NewItemsFound; 
    protected void OnNewItemsFound(object sender) 
    { 
     if(NewItemsFound != null) 
     { 
      NewItemsFound(sender, new System.EventArgs()); 
     } 
    } 
} 

Nachdem ich einige der Kommentare und Antworten zu lesen, ich glaube, mein Problem ist, dass ich ein System.Timers.Timer keine System.Windows.Forms.Timer verwenden.

EDIT:

Nach dem Aufsuchen einer Forms.Timer Erstprüfung Wechsel sieht gut aus (aber keine neuen Elemente existieren noch haben also nicht den benutzerdefinierten Dialog zu sehen ist). Ich habe ein wenig Code hinzugefügt, um die Thread-ID in eine Datei auszugeben, wenn die Update-Methode aufgerufen wird. Mit dem Timer.Timer war die Thread-ID nicht der GUI-Thread, aber mit dem Forms.Timer ist die Thread-ID identisch mit der GUI.

+3

Ja, es ist ein Threading-Problem - aber die Antwort hängt davon ab, ob Sie WPF oder WinForms verwenden: Was ist das? – x0n

+0

Und ich bin überrascht, dass Sie keine Ausnahmen sehen: Welche Version von .NET laufen Sie auf? Können Sie Beispielcode anzeigen? –

+0

Können Sie bitte den Code posten? – TalentTuner

Antwort

15

Which timer verwenden Sie? System.Windows.Forms.Timer löst das Ereignis automatisch im UI-Thread aus. Wenn Sie einen anderen verwenden, müssen Sie Control.Invoke verwenden, um die Methode im UI-Thread aufzurufen.

+0

Das Wechseln zu System.Windows.Forms.Timer hat das Problem gelöst. Vielen Dank. – Tester101

+0

+1000! System.Windows.Forms.Timer löst alle meine sehr frustrierenden "Objekt erstellt auf einem anderen Thread" -Timer Probleme! Vielen Dank! –

+0

wie ein Witz, verbrachte ich einen Tag dafür! Danke und sei dir bewusst – aozan88

1

Sie sollten Forms.Timer hier verwenden, oder wenn Sie eine andere Art von Timer verwenden, Anrufe serialisiert mit .Invoke() UI

0
private static System.Threading.SynchronizationContext _UI_Context; 
    //call this function once from the UI thread 
    internal static void init_CallOnUIThread() 
    { 
     _UI_Context = System.Threading.SynchronizationContext.Current; 
    } 
    public static void CallOnUIThread(Action action, bool asynchronous = false) 
    { 
     if (!asynchronous) 
      _UI_Context.Send((o) => 
      { 
       action(); 
      }, null); 
     else 
      _UI_Context.Post((o) => 
      { 
       action(); 
      }, null); 
    } 
Verwandte Themen