The calling Thread cannot access this object because a different thread owns it. Exception

6.7k views Asked by At
private void Thread1_Exe()
{
    try
    {
        int sleepValT1 = Convert.ToInt32(listBoxT2.SelectedValue);
        int StartLoop = 0;
        int EndLoop = 10000;

        for (int i = StartLoop; i <= EndLoop; i++)
        {
            Dispatcher.BeginInvoke(
            new Action(() => listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepValT1);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

I was trying to call the above function on different thread

private void thread1_Click(object sender, RoutedEventArgs e)
{
    threadBtn1.IsEnabled = false;
    Thread t1 = new Thread(new ThreadStart(Thread1_Exe));

    t1.Start();
}

But the Exception occurs when i select the value from the listbox and try to save it in the variable and then try to pass that value in

Thread.Sleep()

I always get this Exception that the different thread owns this object. Tried Many things. Please help me out where i am doing mistake.

Thanks

2

There are 2 answers

0
Michael Mairegger On BEST ANSWER

Any access to a UI element, no matter if it is read or write, must be called through main UI thread. This thread is accessible through the Dispatcher.

In your code I see a line where this is not the case: when you are calling listBoxT2.SelectedValue

To fix the error call this code on the Dispatcher Thread and save it to a local variable:

int selectedValue;
listBoxT2.Dispatcher.Invoke(() => selectedValue = Convert.ToInt32(listBoxT2.SelectedValue));
   

The rest of the code should work fine.

0
Rytmis On

Your problem is that you are accessing a UI control from a background thread. UIs tend to be single-threaded, so you need to coordinate access to the controls so that it always happens via the UI thread.

The simplest thing you can do is read the value from your listbox before firing up the new thread:

private void Thread1_Exe(int sleepVal)
{
    try
    {
        int StartLoop = 0;
        int EndLoop = 10000;


        for (int i = StartLoop; i <= EndLoop; i++)
        {

            Dispatcher.BeginInvoke(
            new Action(() =>
            listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepVal);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

private void thread1_Click(object sender, RoutedEventArgs e)
{

    threadBtn1.IsEnabled = false;

    int sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue);
    Thread t1 = new Thread(() => Thread1_Exe(sleepValT1));

    t1.Start();
}

Other alternatives include accessing the control via its dispatcher thread:

private void Thread1_Exe()
{
    try
    {
        int sleepValT1;
        listBoxT1.Dispatcher.Invoke(() => sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue));
        int StartLoop = 0;
        int EndLoop = 10000;


        for (int i = StartLoop; i <= EndLoop; i++)
        {

            Dispatcher.BeginInvoke(
            new Action(() =>
            listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
            Thread.Sleep(sleepValT1);
        }

    }
    catch (Exception Ex)
    {
        MessageBox.Show(Ex.Message);
    }
}

private void thread1_Click(object sender, RoutedEventArgs e)
{

    threadBtn1.IsEnabled = false;

    Thread t1 = new Thread(() => Thread1_Exe());

    t1.Start();
}

Generally, you really want to avoid sharing mutable state between threads as much as possible, to keep things easier to reason about.