Michael
Michael

Reputation: 2128

The calling thread cannot access this object

I'm trying to create a timer that returns to the main menu of my WPF application of, let's say, 30 seconds of inactivity. But I get the error "The calling thread cannot access this object because a different thread owns it." and it occurs in the FadeOut() at storyboard.Begin(uc);

I've seen a few solutions involving invoking the dispatcher but I'm not to sure how to apply in my case?

public void ResetScreen()
{
    if (!mainScreen)
    {
        Timer myTimer = new Timer();
        myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
        myTimer.Interval = 1000;
        myTimer.Start();
    }
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    TransitionContent(oldScreen, newScreen);
}

private void FadeIn(FrameworkElement uc)
{
    DoubleAnimation dAnimation = new DoubleAnimation();
    dAnimation.Duration = new Duration(TimeSpan.FromSeconds(1.0));
    dAnimation.From = 0;
    dAnimation.To = 1;
    Storyboard.SetTarget(dAnimation, uc);
    Storyboard.SetTargetProperty(dAnimation, new PropertyPath(OpacityProperty));
    Storyboard storyboard = new Storyboard();
    storyboard.Children.Add(dAnimation);
    storyboard.Begin(uc);
}

private void FadeOut(FrameworkElement uc)
{
    DoubleAnimation dAnimation = new DoubleAnimation();
    dAnimation.Duration = new Duration(TimeSpan.FromSeconds(1.0));
    dAnimation.From = 1;
    dAnimation.To = 0;
    Storyboard.SetTarget(dAnimation, uc);
    Storyboard.SetTargetProperty(dAnimation, new PropertyPath(OpacityProperty));
    Storyboard storyboard = new Storyboard();
    storyboard.Children.Add(dAnimation);
    storyboard.Begin(uc);
}

private void TransitionContent(FrameworkElement oldScreen, FrameworkElement newScreen)
{
    FadeOut(oldScreen);
    FadeIn(newScreen);
}

Upvotes: 0

Views: 915

Answers (2)

Mike Zboray
Mike Zboray

Reputation: 40788

Your problem is that the System.Timers.Timer event runs on a different thread than the UI thread. You can try directly invoking as others have mentioned or you could use DispatcherTimer.

Upvotes: 2

ahmet
ahmet

Reputation: 646

This one might be a solution:

this.Dispatcher.Invoke((Action)(()=>{
      // In here, try to call the stuff which making some changes on the UI
});

Such as:

private void TransitionContent(FrameworkElement oldScreen, FrameworkElement newScreen)
{
     this.Dispatcher.Invoke((Action)(()=>{
          FadeOut(oldScreen);
          FadeIn(newScreen);   
     });
}

Upvotes: 2

Related Questions