简体   繁体   中英

How to update a control on WPF MainWindow

How do I update my label1 text in the code below ? I am getting a "The calling thread cannot access this object because a different thread owns it" error. I have read that others have used Dispatcher.BeginInvoke but I do not know how to implement it in my code.

public partial class MainWindow : Window
{
    System.Timers.Timer timer;

    [DllImport("user32.dll")]        
    public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);

    public struct tagLASTINPUTINFO
    {
        public uint cbSize;
        public Int32 dwTime;
    }

    public MainWindow()
    {
        InitializeComponent();
        StartTimer();
        //webb1.Navigate("http://yahoo.com");
    }

    private void StartTimer()
    {
        timer = new System.Timers.Timer();
        timer.Interval = 100;
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
        Int32 IdleTime;
        LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
        LastInput.dwTime = 0;

        if (GetLastInputInfo(ref LastInput))
        {
            IdleTime = System.Environment.TickCount - LastInput.dwTime;
            string s = IdleTime.ToString();
            label1.Content = s;
        } 
    }
}

You can try something like this:

if (GetLastInputInfo(ref LastInput))
{
    IdleTime = System.Environment.TickCount - LastInput.dwTime;
    string s = IdleTime.ToString();

    Dispatcher.BeginInvoke(new Action(() =>
    {
        label1.Content = s;
    }));
}

Read more about Dispatcher.BeginInvoke Method here

You'd need to save Dispatcher.CurrentDispatcher from the main thread:

public partial class MainWindow : Window
{
    //...
    public static Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
    //...
}

Then, whenever you need to execute something in the context of the main thread, you do:

MainWindow.dispatcher.Invoke(() => {
   label1.Content = s;
});

Note, Dispatcher.BeginInvoke does it asynchronously, unlike Dispatcher.Invoke . You probably want a synchronous call here . For this case, an async call appears to be ok, but often you may want to update the UI on the main thead, then continue on the current thread knowing the update has been done.

Here's a similar question with a complete example.

There are 2 ways to solve this issue:

First, you can use a DispatcherTimer class instead of the Timer class as demonstrated in this MSDN article , which modifies UI elements in Elapsed event on the Dispatcher thread.

Second, with your existing Timer class, you can use the Dispatcher.BegineInvoke() method as per below code in timer_Elapsed event:

label1.Dispatcher.BeginInvoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      new Action(
        delegate()
        {
          label1.Content = s;
        }
    ));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM