0

I'm working on a new GitHub repository called Charms Bar Port using Visual Studio 2022 that requires the UI to show a clock and date at the lower left, as seen on this image.

However, the clock seems to never update regardless of the presence of:

  • Background workers
  • Timers

Is there a good way to continuously keep track of the time in a loop?

Using some code for background workers and/or timers from external sources have never functioned. For example: "8:34" will be stuck on the screen even if the time is "9:00".

    Timer t = new Timer();
    private void Form1_Load(object sender, EventArgs e)
    {
        // Normally, the timer is declared at the class level, so that it stays in scope as long as it
        // is needed. If the timer is declared in a long-running method, KeepAlive must be used to prevent
        // the JIT compiler from allowing aggressive garbage collection to occur before the method ends.
        // You can experiment with this by commenting out the class-level declaration and uncommenting
        // the declaration below; then uncomment the GC.KeepAlive(aTimer) at the end of the method.
        //System.Timers.Timer aTimer;

        // Create a timer and set a two second interval.
        t = new System.Timers.Timer();
        t.Interval = 2000;

        // Create a timer with a two second interval.
        //t = new System.Timers.Timer(2000);

        // Hook up the Elapsed event for the timer.
        t.Elapsed += OnTimedEvent;

        // Have the timer fire repeated events (true is the default)
        t.AutoReset = true;

        // Start the timer
        t.Enabled = true;

        // If the timer is declared in a long-running method, use KeepAlive to prevent garbage collection
        // from occurring before the method ends.
        GC.KeepAlive(t);

    }

    //timer eventhandler
    private void OnTimedEvent(object sender, EventArgs e)
    {
        //update label
            Date.Content = DateTime.Today.ToString("MMMM d");
            Week.Content = DateTime.Today.ToString("dddd");
            Clocks.Content = DateTime.Now.ToString("hh:mm");
        t.Enabled = true;
    }
}
  • 1
    Please Show your attempt – Klaus Gütter Jan 11 '23 at 04:23
  • I've edited the post to include the code in question. – Jayden Montoya Jan 11 '23 at 04:24
  • [Update data to WPF control from another thread](https://www.codeproject.com/Tips/1111432/Update-data-to-WPF-control-from-another-thread) – shingo Jan 11 '23 at 04:31
  • Unless you set the `SynchronizingObject` of the `Timer`, it raises its `Elapsed` event on a secondary thread. You cannot update the UI directly from that thread. [Here](https://www.vbforums.com/showthread.php?498387-Accessing-Controls-from-Worker-Threads&p=3783077&viewfull=1#post3783077) is a post specific to WPF in a thread of mine about accessing controls from worker threads. Note that you can simplify the code a bit using a lambda if you know it will be executed on a secondary thread but that discussion helps you understand the whole process first. – jmcilhinney Jan 11 '23 at 04:47
  • @shingo Practically, do I include the button on the Charms Bar clock and have the program automatically click it? – Jayden Montoya Jan 11 '23 at 04:49

1 Answers1

1

You should use dispatcher to update UI from different thread.

Your code should be:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        _initTimer();
    }
    
    private Timer t = null;
    private readonly Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

    private void _initTimer()
    {
        t = new System.Timers.Timer();
        t.Interval = 1000;
        t.Elapsed += OnTimedEvent;
        t.AutoReset = true;
        t.Enabled = true;
        t.Start();
    }

    private void OnTimedEvent(object sender, ElapsedEventArgs e)
    {
        dispatcher.BeginInvoke((Action)(() =>
        {
            DateTime today = DateTime.Now;                      
            Clocks.Content = today.ToString("hh:mm:ss");
            // do additional things with captured 'today' variable.
        }));
    }
}
KimMeo
  • 320
  • 1
  • 10
  • Thanks, it actually works. "hh:mm:ss" isn't needed as it's meant to be a complete Charms bar port. – Jayden Montoya Jan 11 '23 at 04:59
  • Do not read `DateTime.Now` (or `DateTime.Today`) multiple times in a single update loop, but store it in a variable instead. With your code, it may happen that the date and the time don't allign if an update happens just around midnight. – PMF Jan 11 '23 at 07:37
  • @PMF Your right. This might lead to unnecessary error. I edited the code. – KimMeo Jan 11 '23 at 08:40