0

I need to access the TimerData.textSet field to change the text displayed from a another thread that controls the timing. But a InvalidOperationException is thrown. Is there a solution to this problem.

namespace Scilca.KBL
{
    public class TimerData
    {
        public Run textSet;
        public ProgressBar statusTimer;

        public TimerData(Run run, ProgressBar statusTimer)
        {
            textSet = run;
            this.statusTimer = statusTimer;
        }
    }

    /// <summary>
    /// Interaction logic for KBLSessionWindow.xaml
    /// </summary>
    public partial class KBLSessionWindow : Window
    {
        private int leftTime = 60;
        private static Run run;
        private static ProgressBar progressBar;

        public int TimeLeftOver
        {
            get { return leftTime; }
        }

        public KBLSessionWindow()
        {
            InitializeComponent();
            run = runSecondTime;
            progressBar = timeProgress;
            Thread timerThread = new Thread(new ParameterizedThreadStart(startTimer));
            timerThread.Start(new TimerData(run, progressBar));
        }

        public void startTimer(Object td)
        {
            TimerData timerData = (TimerData)td;
            int time = 60;
            while (true)
            {
                Thread.Sleep(1000);
                time -= 1;
                if (time == 0)
                    time = 60;
                Console.WriteLine(timerData.textSet.Text);
                timerData.textSet.Text = time.ToString(); // InvalidOperationException
                timerData.statusTimer.Value = time * 100 / 60;
            }
        }
    }
}
4

1 Answer 1

1

It looks like you are trying to access an UI element from a non-ui thread.

Whenever you update your UI elements from a thread other than the main thread, you need to use:

Application.Current.Dispatcher.Invoke(() =>
{
        // your code here.
        timerData.textSet.Text = time.ToString();
        timerData.statusTimer.Value = time * 100 / 60;
});

otherwise you will get a System.InvalidOperationException

From MSDN:

An System.InvalidOperationException is thrown when a method of an object is called when the state of the object cannot support the method call. The exception is also thrown when a method attempts to manipulate the UI from a thread that is not the main or UI thread.

Unrelated to your issue, I would suggest using a timer (see below) instead of creating a new thread every time, this would be more efficient since Timer is using the Thread Pool:

Timer myTimer = new Timer();
myTimer.Elapsed += new ElapsedEventHandler(DisplayTimeEvent);
myTimer.Interval = 1000; // 1000 ms is one second
myTimer.Start();

public static void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
    // code here will run every second
}
Sign up to request clarification or add additional context in comments.

2 Comments

this.Dispatcher looks wrong, Dispatcher is a type, this refer to a member trough the current class, you should use Application.Current.Dispatcher to refer to the Dispatcher which created UI
I have updated the example. I didn't mean for the code to be used verbatim but there you go..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.