0

I am building an iOS app and I'm trying to change the background image every few seconds. I set up a timer using code from here: https://developer.xamarin.com/api/type/System.Threading.Timer/

My code looks like this:

using System;
using System.Threading;

using UIKit;

namespace TestApp
{
    public partial class ViewController : UIViewController
   {
    // New Timer
    class BackgroundTimer
    {
        public int counter = 0;
        public Timer tmr;

    }
    // Load screen
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        BackgroundTimer s = new BackgroundTimer();
        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = new TimerCallback(ChangeBackground);

        // Create a timer that waits three seconds, then invokes every three seconds.
        Timer timer = new Timer(timerDelegate, s, 3000, 3000);

        // Keep a handle to the timer, so it can be disposed.
        s.tmr = timer;

        void ChangeBackground(Object state)
        {
            BackgroundTimer t = (BackgroundTimer)state;
            t.counter++;
            Background.Image = UIImage.FromBundle("HydePark");
        }

When I run it in the simulator, I get the following error:

UIKit.UIKitThreadAccessException has been thrown

UIKit Consistency error: you are calling a UIKit method that can only 
be invoked from the UI thread.

I'm not sure what that means.

Update/Edit: (23 Jul 2017)

The question below solved my issue. I want to cycle images so I made a random generator but it only cycles the images once.

 // Load screen
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        // Random number generator 
        Random RandomImage = new Random();
        int RandomImg = RandomImage.Next(1, 6);
        string image = "";

        // Switch statement for displaying different messages
        switch (RandomImg)
        {
            case 1:
                image = "Image1";
                break;
            case 2:
                image = "Image2";
                break;
            case 3:
                image = "Image3";
                break;
            case 4:
                image = "Image4";
                break;
            case 5:
                image = "Image5";
                break;
        }

        BackgroundTimer s = new BackgroundTimer();
        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = new TimerCallback(ChangeBackground);

        // Create a timer that waits three seconds, then invokes every three seconds.
        Timer timer = new Timer(timerDelegate, s, 3000, 3000);

        // Keep a handle to the timer, so it can be disposed.
        s.tmr = timer;

        void ChangeBackground(Object state)
        {
            BackgroundTimer t = (BackgroundTimer)state;
            t.counter++;
            InvokeOnMainThread(() =>
            {
                Background.Image = UIImage.FromBundle(image);
            });

        }
Zailyn Tamayo
  • 112
  • 1
  • 9

1 Answers1

3

Updating the UI requires that you are on the main thread (UI thread), placing your Background.Image call within an InvokeOnMainThread will solve the UIKit exception:

void ChangeBackground(Object state)
{
    BackgroundTimer t = (BackgroundTimer)state;
    t.counter++;
    InvokeOnMainThread(() =>
    {
        Background.Image = UIImage.FromBundle("HydePark");
    });
}

Xamarin has a guide that provides an overview of why/how these needs to be done:

SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • This works! Thank you so much! I have an additional question if you can please help. I've edited/updated my question. I want it to cycle images but it only cycles once. – Zailyn Tamayo Jul 23 '17 at 17:48