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;
            }
        }
    }
}
Chris Shain
  • 50,833
  • 6
  • 93
  • 125
Shukant Pal
  • 706
  • 6
  • 19
  • 1
    Do *not* directly access gui components from other threads. If you are using winforms, you can use [`invoke`](https://msdn.microsoft.com/de-de/library/system.windows.forms.control.invoke(v=vs.110).aspx) for that, see for example: http://stackoverflow.com/questions/6650691/invoke-in-windows-forms – Nico Oct 27 '16 at 14:04
  • I am using WPF. So what should I do? – Shukant Pal Oct 27 '16 at 14:08
  • The exception said that the object is owned by another thread. – Shukant Pal Oct 27 '16 at 14:08
  • 1
    Possible duplicate of [InvalidOperationException when multithreading in WPF](http://stackoverflow.com/questions/14773183/invalidoperationexception-when-multithreading-in-wpf) – Sami Kuhmonen Oct 27 '16 at 14:11

1 Answers1

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
}
brakeroo
  • 1,407
  • 13
  • 24
  • 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 – freakydinde Oct 27 '16 at 14:16
  • I have updated the example. I didn't mean for the code to be used verbatim but there you go.. – brakeroo Oct 28 '16 at 01:55