Search code examples
c#user-controlstimerchildwindow

I get an error about using a different thread?


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);
    }
}

Solution

  • 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