Reputation: 97
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
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.
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();
}
}
}
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();
}
}
}
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."
}
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
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
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