6
namespace PizzaSoftware.UI
{
    /// <summary>
    /// Interaction logic for LoginForm.xaml
    /// </summary>
    public partial class LoginForm : Window
    {
        public LoginForm()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Timer timer = new Timer(1000);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = true;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lblCurrentTime.Content = DateTime.Now.ToShortTimeString();
        }
    }
}

Basically, I'm just trying to have a label on my form that displays the current time. I'm using a Timer as suggested in another of my SO question.

I'm receiving the error in title. What can I do to solve this?

2 Answers2

26

Well, the simplest approach is to use a DispatcherTimer - which will fire its Tick event in the dispatcher thread:

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1000);
timer.IsEnabled = true;
timer.Tick += timer_Elapsed;

Alternatively, you can use Dispatcher.Invoke/BeginInvoke to execute a delegate in the dispatcher thread... but that will be more complicated. This would be a better approach if you needed to do significant work on each timer tick and then just update the UI with the result - but as you're not doing much work at all here, it's fine to just do it all in the UI thread.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks Jon, after reading the cliffnote on MSDN, it seems the DispatcherTimer runs on the UI thread by default, no? –  Mar 24 '11 at 18:04
2

Didn't realize this was a WPF app. You need to get a hold of the Dispatcher, which you can do in the Constructor:

    private Dispatcher _dispathcer;

    public LoginForm()
    {
        InitializeComponent();
        _dispathcer = Dispathcer.CurrentDispather;
    }



    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _dispathcer.Invoke(new Action( ()=> { lblCurrentTime.Content = DateTime.Now.ToShortTimeString();});
    }
BFree
  • 102,548
  • 21
  • 159
  • 201
  • You can just access the `Dispatcher` property in the `timer_Elapsed` method - there's no need to set it in the constructor. And if you use a DispatcherTimer, you don't need to go to all this trouble at all :) – Jon Skeet Mar 24 '11 at 18:30
  • @Jon: Wouldn't you then be accessing the Dispatcher of the background thread? My understanding was that timer_Elapsed gets called on a background thread, and therefore the Dispatcher.CurrentDispatcher would be the one from the background thread. – BFree Mar 24 '11 at 19:00
  • No, you'd be accessing the dispatcher of the Window. I wasn't suggesting using Dispatcher.CurrentDispatcher - I was suggesting using the Dispatcher property that Window inherits from DispatcherObject. – Jon Skeet Mar 24 '11 at 19:31