user1003676
user1003676

Reputation: 97

Invalid cross-thread access. error

I have a web form in silverlight.

On action of some button click i want to update a another control like chart, Textbox etc

In the mean time when it fills the chart or textbox, i need to show a busy indicator

  1. Busy indicator should show first in screen
  2. behind the chart value should get update
  3. Chart value will reflect in screen
  4. Busy indicator should hide

But the problem is when i try using Thread I am getting an error "Invalid cross-thread access.". As the thread is accessing the UI control. The 4 steps which i have tried is as follows.

Any valuable suggestion how to solve this issue.

Step 1 => Tried Thread

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;
using System.Windows.Threading;


namespace SilverlightApplication2
{
  public partial class MainPage : UserControl
    {

        public MainPage()
        {
            InitializeComponent();



        }

        private void test1()
        {


            for (int i = 1; i < 10000; i++)
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }
        textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
            busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
        }



     private void button1_Click(object sender, RoutedEventArgs e)
         {
             busyIndicator1.IsBusy = true;

             Thread th1 = new Thread(test1);
             th1.Start();

         }

    }
}

step 2 => Tried BackgroundWorker

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;
using System.Windows.Threading;


namespace SilverlightApplication2
{
  public partial class MainPage : UserControl
    {

        public MainPage()
        {
            InitializeComponent();



        }

        private void test1()
        {


            for (int i = 1; i < 10000; i++)
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }
        textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
            busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
        }



     private void button1_Click(object sender, RoutedEventArgs e)
         {
             busyIndicator1.IsBusy = true;

            var bw = new BackgroundWorker();
            bw.DoWork += (s, args) =>
            {
                test1();  //Stuff that takes some time
            };
            bw.RunWorkerCompleted += (s, args) =>
            {
                busyIndicator1.IsBusy = false;
            };
            bw.RunWorkerAsync();              
         }

    }
}

Step 3 => Tried to raise an Event from the code behind

public delegate void LinkToEventHandler();
public static event LinkToEventHandler Evt;

 private void button1_Click(object sender, RoutedEventArgs e)
 {
     busyIndicator1.IsBusy = true;

     Evt += new LinkToEventHandler(this.test1);
     Evt();
 }



private void test1()
{


    for (int i = 1; i < 10000; i++)
    {
        System.Diagnostics.Debug.WriteLine(i.ToString());
    }
    textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
    busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
}

step 4 => Tried Binding the Busyindicator

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;
using System.Windows.Threading;


namespace SilverlightApplication2
{
    public partial class MainPage : INotifyPropertyChanged
    {
        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
        public const string IsBusyPropertyName = "busyIndicator1";
        private bool _isBusy = false;
        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }
            set
            {
                if (_isBusy != value)
                {
                    _isBusy = value;
                    RaisePropertyChanged(IsBusyPropertyName);
                }
            }
        }

        protected void RaisePropertyChanged(string propertyName)
        {
            System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
            if ((propertyChanged != null))
            {
                propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }


        private void button1_Click(object sender, RoutedEventArgs e)
        {

            IsBusy = true;

            test1();

            IsBusy=false;

        }

    }


    public partial class MainPage : UserControl
    {

        public MainPage()
        {
            InitializeComponent();



        }


        private void test1()
        {


            for (int i = 1; i < 10000; i++)
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }


        }



    }
}

Note:- I want a solution which should work in Web form in silverlight not the windows form

Upvotes: 0

Views: 9000

Answers (2)

Jack7
Jack7

Reputation: 1341

This should work for you. Essentially place your processing code in a thread and get back your UI control via a Dispatcher

 public partial class MainPage : UserControl
    {
        private Thread _thread1;

        public MainPage()
        {
            InitializeComponent();
        }

        private void StartThreads()
        {
            _thread1 = new Thread(test1);
            _thread1.Start();
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            busyIndicator1.IsBusy = true;
            StartThreads();
        }

        private void test1()
        {
            for (int i = 1; i < 10000; i++)
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }
            this.Dispatcher.BeginInvoke(delegate()
            {
                textBox1.Text = "test";
                busyIndicator1.IsBusy = false;
            });
        }
    }

Upvotes: 2

Samuel Slade
Samuel Slade

Reputation: 8623

The reason you are getting this error is because UI methods can only be invoked on the UI (aka Dispatcher) thread. To overcome this when wanting to perform UI operations on another thread, you should invoke the action on the main UI thread. (See below)

Inline Invocation

// Disable some control
this.Dispatcher.BeginInvoke(new Action(() => this.SomeControl.IsEnabled = false));

Method-Driven Invocation

private void SomeMethodRunningOnAnotherThread()
{
    // ... perform some operations

    // Update the UI
    UpdateUI();

    // ... perform more operations
}

private void UpdateUI()
{
    // Make sure we're running on the UI thread
    if (!CheckAccess())
    {
        this.Dispatcher.BeginInvoke(new Action(UpdateUI));
        return;
    }

    // Disable some control
    this.SomeControl.IsEnabled = false;
}

In most cases, the second approach may be better - particularly when performing multiple UI operations. It is worth noting that these UI actions will be executed on the UI thread once the UI thread has become idle, so if your already holding it up doing something else, you won't see the update. Also, by using BeginInvoke you don't hold up the calling thread.

Upvotes: 3

Related Questions