locked
Please Help Me With My First WPF Application RRS feed

  • Question

  • Hello all, I have been programming with windows forms and asp.net for a few years now, and so I thought I would try my hand at WPF. I created a very simple app where I used Blend to place a progress bar control in my Window1.xaml file. I then used Visual Studio 2008 to add a timer control (why in the world does WPF not contain a timer control...are you kidding me?) in the code behind file. I then put in some code to adjust the progress bar so I could have a look at the WPF progress bar control in action. Here's the code behind...

    -------
    using System.Windows;
    using System.Timers;

    namespace ProgressBarTest
    {
       public partial class Window1 : Window
       {
          public Window1()
          {
             InitializeComponent();
             this.Loaded += new RoutedEventHandler(Window1_Loaded);
          }

          void Window1_Loaded(object sender, RoutedEventArgs e)
          {
             Timer tmrMain = new Timer();
             tmrMain.Elapsed += new ElapsedEventHandler(tmrMain_Elapsed);
             tmrMain.Interval = 500;
             tmrMain.Enabled = true;
          }

          void tmrMain_Elapsed(object sender, ElapsedEventArgs e)
          {
             if (this.pbrMain.Value < this.pbrMain.Maximum)
             {
                this.pbrMain.Value++;
             }
          }
       }
    }
    -------

    Now, everytime I run the code I get the following error...

    -------

    The calling thread cannot access this object because a different thread owns it.

    -------

    I do have some experience working with Threads (delegates, ThreadStart, Invoke, etc...) with windows forms.

    Can someone please tell me why this doesn't work in WPF and exactly how I can fix it?

    Thanks!
    Monday, August 18, 2008 8:50 PM

Answers

  • Greetings!

    I suspect that what's happening here is that your timer is running in a different thread, which would explain the error. Try using a DispatcherTimer instead:

    void Window1_Loaded(object sender, RoutedEventArgs e) 
        Timer tmrMain = new DispatcherTimer(); 
        tmrMain.Elapsed += new ElapsedEventHandler(tmrMain_Elapsed); 
        tmrMain.Interval = new TimeSpan(500); 
        tmrMain.Enabled = true

    From the MSDN documentation:
    If a System.Timers..::.Timer is used in a WPF application, it is worth noting that the System.Timers..::.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. For an example of using a System.Timers..::.Timer, see Disable Command Source via System Timer Sample. Reasons for using a DispatcherTimer opposed to a System.Timers..::.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.


    You should also bear in mind that the tick value for a TimeSpan in WPF is only 100 nanoseconds. So you'll probably want to have it update less often than every 0.05 milliseconds ;)

    Good luck!

    Thanks,
    Emmanuel



    Monday, August 18, 2008 9:20 PM

All replies

  • Greetings!

    I suspect that what's happening here is that your timer is running in a different thread, which would explain the error. Try using a DispatcherTimer instead:

    void Window1_Loaded(object sender, RoutedEventArgs e) 
        Timer tmrMain = new DispatcherTimer(); 
        tmrMain.Elapsed += new ElapsedEventHandler(tmrMain_Elapsed); 
        tmrMain.Interval = new TimeSpan(500); 
        tmrMain.Enabled = true

    From the MSDN documentation:
    If a System.Timers..::.Timer is used in a WPF application, it is worth noting that the System.Timers..::.Timer runs on a different thread then the user interface (UI) thread. In order to access objects on the user interface (UI) thread, it is necessary to post the operation onto the Dispatcher of the user interface (UI) thread using Invoke or BeginInvoke. For an example of using a System.Timers..::.Timer, see Disable Command Source via System Timer Sample. Reasons for using a DispatcherTimer opposed to a System.Timers..::.Timer are that the DispatcherTimer runs on the same thread as the Dispatcher and a DispatcherPriority can be set on the DispatcherTimer.


    You should also bear in mind that the tick value for a TimeSpan in WPF is only 100 nanoseconds. So you'll probably want to have it update less often than every 0.05 milliseconds ;)

    Good luck!

    Thanks,
    Emmanuel



    Monday, August 18, 2008 9:20 PM
  • Not sure, but I think I've fixed this. I changed the code to the following. I modeled it after a code sample I found in the WPF FAQ thread...

          void t1_Elapsed(object sender, ElapsedEventArgs e)
          {
             pbrMain.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
                {
                   pbrMain.Value++;
                }));
          }

    JP
    Monday, August 18, 2008 9:21 PM
  • Like egreene said, you shouldn't be using that kind of timer here.
    Controls for WPF and Windows Forms at http://www.divelements.co.uk
    Monday, August 18, 2008 9:35 PM