Reputation: 3156
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;
}
}
}
Upvotes: 4
Views: 3697
Reputation: 61656
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.
Upvotes: 2
Reputation: 8502
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;
}
));
Upvotes: 1
Reputation: 11945
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
Upvotes: 6