1

When I click my ActionButton, there is a timer that starts and after 3 seconds, it must fire a methode to change the current ContentPage to the another page. But i get a message : The calling thread cannot access this object because a different thread owns it. I dont understand what i am doing wrong. But if i put the ChangeContent() method in the click_event, it works, but in the _tm_elapsed it doenst work?

using smartHome2011.FramePages;
using System.Timers;

public partial class AuthenticationPage : UserControl
{
    private MainWindow _main;
    private Storyboard _storyboard;
    private Timer _tm = new Timer();
    private HomeScreen _homeScreen = new HomeScreen();

    public AuthenticationPage(MainWindow mainP)
    {
        this.InitializeComponent();
        _main = mainP;
    }

    private void ActionButton_Click(object sender, System.EventArgs eventArgs)
    {
        _main.TakePicture();
        identifyBox.Source = _main.source.Clone();
        scanningLabel.Visibility = Visibility.Visible;
        _storyboard = (Storyboard) FindResource("scanningSB");
        //_storyboard.Begin();
        Start();
    }

    private void Start()
    {
        _tm = new Timer(3000);
        _tm.Elapsed += new ElapsedEventHandler(_tm_Elapsed);
        _tm.Enabled = true;
    }

    private void _tm_Elapsed(object sender, ElapsedEventArgs e)
    {
        ((Timer) sender).Enabled = false;
        ChangeContent();
        //MessageBox.Show("ok");
    }

    private void ChangeContent()
    {
        _main.ContentPage.Children.Clear();
        _main.ContentPage.Children.Add(_homeScreen);
    }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Letoir
  • 395
  • 7
  • 15

3 Answers3

4

Description

You have to use Invoke to ensure that the UI Thread (the thread who has created your Control) will execute that.

1. If you are doing Windows Forms then do this

Sample

private void ChangeContent()
{
    if (this.InvokeRequired)
    {
        this.Invoke(new MethodInvoker(ChangeContent));
        return;
    }

    _main.ContentPage.Children.Clear();
    _main.ContentPage.Children.Add(_homeScreen);
}

2. If you are doing WPF then do this

private void _tm_Elapsed(object sender, ElapsedEventArgs e)
{
    ((Timer) sender).Enabled = false;
    this.Dispatcher.Invoke(new Action(ChangeContent), null);
    //MessageBox.Show("ok");
}

More Information

Windows Forms

WPF

dknaack
  • 60,192
  • 27
  • 155
  • 202
  • sorry but i cant find the proper namespace for InvokeRequired, i tried the namespaces on the MSDN site :s – Letoir Jan 02 '12 at 10:53
  • `InvokeRequired` is part of any Control, UserControl, Form and more. So you can do `this.InvokeRequired`... is this not available ? – dknaack Jan 02 '12 at 11:00
  • This is strange. I copied your code and it works fine. Which version of .NET are you using ? – dknaack Jan 02 '12 at 11:11
  • but this a Usercontrol and not a form or page ? – Letoir Jan 02 '12 at 11:16
  • Your `UserControl` comes from `smartHome2011.FramePages` right ? I cant give you more help because i don't know what `smartHome2011.FramePages.UserControl` is. If your UserControl is placed on a Windows Form then try this. `(this.Parent as System.Windows.Forms.Form).InvokeRequired`. – dknaack Jan 02 '12 at 11:18
  • I have a MainWindow, there is a Grid called ContentPage, in this ContentPage i update my content each time. But every page that i made is a UserControl, and all the pages are located in smartHome2011.FramePages. My UserControl is placed upon my windows form i get an error with the code u wrote above. it says : Cannot convert type 'System.Windows.DependencyObject' to 'Form' via a built in conversion? – Letoir Jan 02 '12 at 11:28
  • Is `UserControl` from `System.Windows.Forms` ? It looks like that it is not. – dknaack Jan 02 '12 at 11:29
  • from System.Windows.Controls.UserControl – Letoir Jan 02 '12 at 11:35
  • Aaahh i think i got it. You are doing WPF not Windows Forms. So change your `_tm_Elapsed` method to call `ChangeContent` like this `this.Dispatcher.Invoke(new Action(ChangeContent), null);`. – dknaack Jan 02 '12 at 11:44
  • Thanks buddy it works, i dont know what it is but im sure gratefull for it :) – Letoir Jan 02 '12 at 12:13
  • sorry to disturb you, but i have a chart on the _homeScreen, it dissapeared, i mean the chart screen is there, but it doesnt get filled with data, does this have anything to do with the Dispacth or invoke? i dont know either of them, so maybe its this, and the _homeScreen worked perfectly before this. – Letoir Jan 02 '12 at 12:29
  • No problem. Sorry but thats not enough information to help you. – dknaack Jan 02 '12 at 12:31
  • i fugured it out, but i think its something with the threads! thx – Letoir Jan 02 '12 at 12:49
1

The logic executed in the Elapsed event of the Timer is run on a separate thread from the rest of your code. This thread cannot access objects on the main/GUI thread.

This thread should help you find out how to do it: How to update the GUI from another thread in C#?

Community
  • 1
  • 1
snurre
  • 3,045
  • 2
  • 24
  • 31
1

I suspect you are using a System.Threading.Timer. You can avoid cross thread operation by just using a Windows.Forms timer: http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx That timer uses regular messages and the event occours on the same thread of the UI. The event to use is no more called "Elapsed", but "Tick" read the doc here: http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.tick.aspx

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115