2010-10-18 18 views
7

W mojej aplikacji używam licznika czasu do sprawdzania aktualizacji w kanale RSS, jeśli zostaną znalezione nowe elementy, wyświetlam niestandardowe okno dialogowe, aby poinformować użytkownika. Kiedy uruchomię czek ręcznie, wszystko działa świetnie, ale gdy automatyczne sprawdzanie zostanie uruchomione w zegarach Elapsed, niestandardowe okno dialogowe nie zostanie wyświetlone.Metoda wywołania na wątku GUI z wątku timerów

Po pierwsze jest to problem z wątkiem? (Zakładam, że tak jest, ponieważ zarówno ręczne, jak i automatyczne sprawdzenie używa tego samego kodu).

Po uruchomieniu automatycznego sprawdzania, czy muszę wywołać metodę, która uruchamia kontrolę z programu obsługi zdarzeń Czas oczekiwania?

Czy jest coś, co powinienem zrobić w mojej klasie okna dialogowego?

Edytuj: to jest aplikacja WinForm.

Oto przykład kodu. (Proszę nie wskazywać błędów składni w tym przykładzie kodu, to tylko prosty przykład, a nie prawdziwy kod).

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()); 
     } 
    } 
} 

Po przeczytaniu niektórych komentarzy i odpowiedzi, myślę, że moim problemem jest to, że używam nie System.Timers.TimerSystem.Windows.Forms.Timer.

EDIT:

Po zmianie do Forms.Timer wstępnych testów wygląda dobrze (ale żadne nowe elementy istnieją jeszcze tak nie widać okna niestandardowe). Dodałem trochę kodu, aby wyprowadzić identyfikator wątku do pliku po wywołaniu metody aktualizacji. Za pomocą Timers.Timer identyfikator wątku nie był wątkiem GUI, ale przy użyciu Forms.Timer identyfikator wątku jest taki sam jak GUI.

+3

Tak, jest to problem z gwintowaniem - ale odpowiedź zależy od tego, czy używasz WPF, czy WinForm: co to jest? – x0n

+0

I jestem zaskoczony, że nie widzisz żadnych wyjątków: w jakiej wersji .NET to działasz? Czy możesz pokazać przykładowy kod? –

+0

Czy możesz opublikować kod? – TalentTuner

Odpowiedz

15

Which timer Czy korzystasz? System.Windows.Forms.Timer automatycznie uruchamia zdarzenie w wątku interfejsu użytkownika. Jeśli używasz innego, musisz użyć Control.Invoke, aby wywołać metodę na wątku UI.

+0

Zmiana na System.Windows.Forms.Timer rozwiązała problem. Dziękuję Ci. – Tester101

+0

+1000! System.Windows.Forms.Timer rozwiązuje wszystkie moje bardzo frustrujące problemy z timerem "Obiekt utworzony na innym wątku"! Dzięki! –

+0

jak żart, spędziłem dzień na to! Dzięki i bądź świadomy – aozan88

1

Należy użyć Forms.Timer tutaj, lub jeśli używasz innego rodzaju zegarów, szeregować połączeń na interfejsie z .Invoke()

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); 
    } 
Powiązane problemy