5

I have a C# Windows form that has a couple of text boxes and buttons. Also it has a datagrid view that shows a sql table. I create a refresh button that allow me to refresh the table so I can see the updated items inside the table. I was wondering is there any way to refresh the table by it self. Like every 10 second.Or instead of table, perhaps the entire form loaded or refreshed by itself every 10 second?

Servy
  • 202,030
  • 26
  • 332
  • 449
GoGo
  • 2,727
  • 5
  • 22
  • 34
  • so you want to run an SQL query ever second too? if so that would be a horrible thing to do! – Mo Patel Apr 17 '14 at 15:22
  • 3
    Every 10 seconds, and I think we don't have enough information to declare it horrible. – zmarks22 Apr 17 '14 at 15:28
  • 1
    I fail to see the wrongness in the OPs Question. There is pushing and polling and sometimes one of them is better and the other not :-) And the title of the question is much searched for ;-) – Xan-Kun Clark-Davis Dec 10 '15 at 13:51

4 Answers4

24

Use a Timer control, it's UI thread invoked and a control available to you via the Form Designer.

private void Form1_Load(object sender, EventArgs e)
{
    System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
    timer.Interval = (10 * 1000); // 10 secs
    timer.Tick += new EventHandler(timer_Tick);
    timer.Start();
}

private void timer_Tick(object sender, EventArgs e)
{
   //refresh here...
}
T McKeown
  • 12,971
  • 1
  • 25
  • 32
  • 4
    Please note that it is the `System.Windows.Forms.Timer` as @"Sudhakar Tillapudi" said in this (as-well) correct answer. You should never use `System.Threading.Timer`. `System.Windows.Forms.Timer` *invokes* the callback on the GUI-Thread whereas `System.Threading.Timer` uses a thread available in the ThreadPool, and you will get a cross-threading exception: `InvalidOperationException` with the message: "Control control name accessed from a thread other than the thread it was created on". WPF provides the `DispatcherTimer` similar to the `System.Windows.Forms.Timer` with additional features. – jeromerg Apr 17 '14 at 15:43
  • i updated my example to make it clear. – T McKeown Sep 01 '23 at 21:07
3

You can use System.Windows.Forms.Timer Control to refresh your form controls.

Try This:

System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
timer1.Interval=5000;//5 seconds
timer1.Tick += new System.EventHandler(timer1_Tick);
timer1.Start();

private void timer1_Tick(object sender, EventArgs e)
{
     //do whatever you want 
     RefreshControls();
}
Sudhakar Tillapudi
  • 25,935
  • 5
  • 37
  • 67
  • 1
    I didn't down vote but my guess is the code that creates and starts the timer is not in a function. – T McKeown Apr 17 '14 at 15:30
  • I had to be very careful with the naming of methods, as there is a lot of "Refresh"-ing and "Update"-ing already going on in WinForms and I easily got confused, esp. when overloading controls. Not a real problem, just a warning, I got very confused when calling my "Refresh" method (and ReSharper too :-) ). – Xan-Kun Clark-Davis Dec 10 '15 at 12:00
1

And this is the way I would usually handle it.

Scenario: Some Thread should update something every n-seconds, but we want to be able to trigger an update before that time runs out without risking to block anything.

    private static readonly TimeSpan timeout = TimeSpan.FromSeconds(10);

    private static readonly object Synchronizer = new { };

    public static void idle()
    {
        //make sure, it is only called from the Thread that updates.
        AssertThread.Name("MyUpdateThreadName");
        lock (Synchronizer) {
            Monitor.Wait(Synchronizer, timeout);
        }
    }

    public static void nudge()
    {
        //anyone can call this
        lock (Synchronizer) {
            Monitor.PulseAll(Synchronizer);
        }
    }

Here, idle() would be called from a Thread that does the update, and nudge() could be called from anywhere to start an update before the timeout expires.

It works very reliable even when a lot of nudges come in very fast, due to the complex interaction between Wait and Pulse - considering the locked state of the Synchronizer. This also has the neat side effect of never dead(b)locking the update thread.

Of course, if the update involves GUI stuff, you would have to take the whole InvokeRequired tour. That means in the while loop of the update thread it looks something like

        if (MyForm.InvokeRequired)
            MyForm.BeginInvoke(sendinfo, message);
        else
            sendinfo(message);

with sendinfo probably being some kind of Action or Delegate. And you would never, ever, ever call idle() directly from the GUI thread!

The only Not-So-Obvious behaviour I could find so far: If you have a lot of nudges very fast and the Thread is actually updating a GUI, there is a huge difference between Invoke() and BeginInvoke(). Depending on what you want, Invoke actually gives the GUI time to react to interactions and BeginInvoke can quickly flood the message pump and make the GUI unresposive (which in my case is (weirdly enough) the the wanted behaviour :-) ).

Xan-Kun Clark-Davis
  • 2,664
  • 2
  • 27
  • 38
-2

I am not sure if both answers are really a good idea. What happens if the GUI update (God beware, but it's possible, just imagine a Windows Update in the background :-) ) takes longer than 1 second. Wouldn't that lead to a clogged message pump of the from creation thread?

I just found the answer over here: What if a timer can not finish all its works before the new cycle time arrives?

If we use the correct Timer class, everything is fine, or to cite Mr. Jim Mischel: If you're using System.Windows.Forms.Timer, then a new tick won't occur until the previous one is finished processing.

I also stop the timer in the beginning of the tick event and start it again afterwards, but this is only because I don't need two consecutive updates.

Ususally I would use Monitor Wait/Pulse, but in this case, it is very comfortable, that the timer event gets executed in the gui thread, so no ned to Invoke anything.

As I also need to update manually (i.e. not from the tick), my code looks something like this:

Right after InitializeComponent()

    //if you use the wrong one here, you will get in great trouble :-)
    guiUpdateTimer = new System.Windows.Forms.Timer { Interval = 1000 };
    guiUpdateTimer.Tick += (sender, args) => updateGUI();
    guiUpdateTimer.Start();

And

    private void updateGUI()
    {
        guiUpdateTimer.Stop();
        unsafe_updateGUI(); //inhere we actually access the gui
        guiUpdateTimer.Start();
    }

If you wrap the unsafe_updateGUI() call in a proper InvokeRequired check, it can even be called from outside the GUI thread.

Oh yes, and for the OP scenario, this most probably is not the best way to go...

Community
  • 1
  • 1
Xan-Kun Clark-Davis
  • 2,664
  • 2
  • 27
  • 38