10

In my application I am using a timer to check for updates in an RSS feed, if new items are found I pop up a custom dialog to inform the user. When I run the check manually everything works great, but when the automatic check runs in the timers Elapsed event the custom dialog is not displayed.

First of all is this a thread issue? (I am assuming it is because both the manual and automatic check use the same code).

When I run the automatic check, do I have to invoke the method that runs the check from the Timers Elapsed event handler?

Is there something I need to do in my custom dialog class?

Edit: this is a winforms application.

Here is an example of what the code is like. (Please don't point out syntax errors in this code example, this is just a simple example not real 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());
        }
    }
}

After reading some of the comments and answers, I think my problem is that I am using a System.Timers.Timer not a System.Windows.Forms.Timer.

EDIT:

After changing to a Forms.Timer initial testing looks good (but no new items exist yet so have not seen the custom dialog). I added a bit of code to output the thread ID to a file when the update method is called. Using the Timers.Timer the thread ID was not the GUI thread, but using the Forms.Timer the thread ID is the same as the GUI.

Tester101
  • 8,042
  • 13
  • 55
  • 78
  • 3
    Yep, it's a threading issue - but the answer depends on whether you are using WPF or WinForms: which is it? – x0n Oct 18 '10 at 12:30
  • And I'm surprised you're not seeing any exceptions: what version of .NET are you running this on? Can you show some sample code? – Eamon Nerbonne Oct 18 '10 at 12:32
  • Can you please post the code ? – TalentTuner Oct 18 '10 at 12:34
  • @Tester101 - If you drag and drop the System.Timers.Timer from toolbox on the form it will automatically fire events on GUI thread. See the article I linked to in my answer. – Giorgi Oct 18 '10 at 13:27
  • ObjectThatDoesWork doesn't define NewItemsFound. Posting the actual code would make it much easier to help you – smirkingman Oct 18 '10 at 13:32
  • @Giorgi: The timer is not on a Form, that is why I used a System.Timers.Timer initially. – Tester101 Oct 18 '10 at 14:49
  • @smirkingman: NewItemsFound is a boring old event definition, so I didn't think it would be that important to the example. – Tester101 Oct 18 '10 at 14:50
  • I'd love to help, but if you won't cooperate... Anyway, you're off on the wrong foot, timers are almost never the solution to this kind of problem, sorry. – smirkingman Oct 18 '10 at 15:43
  • @smirkingman: What should I use other than a timer? Isn't this exactly what a timer was designed for, to run code every x amount of time? – Tester101 Oct 18 '10 at 16:27

4 Answers4

20

Which timer are you using? System.Windows.Forms.Timer automatically fires the event on the UI thread. If you are using other one you will need to use Control.Invoke to call the method on UI thread.

Giorgi
  • 30,270
  • 13
  • 89
  • 125
1

You should use Forms.Timer here, or if you use other kind of timers, serialize calls to UI with .Invoke()

Daniel Mošmondor
  • 19,718
  • 12
  • 58
  • 99
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);
    }
Koray
  • 1,768
  • 1
  • 27
  • 37
0

Is your application a WPF-Application? If so, you must delegate the work from your background-thread to the Dispatcher associated with the UI thread.

Post some code, so you can get better help and have a look at the Dispatcher class http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx

cordellcp3
  • 3,557
  • 1
  • 17
  • 14