I am in mid of an MVVM application. Here I have a collection (ObservableCollection) that may have add, delete operations done from a different thread.
Here is the code. I have tried to keep it as complete as possible:
private Thread _thread = null;
private Dispatcher _UIDispatcher = null;
public ObservableCollection<string> ListOfStrings { get; private set; }
The ctor:
public MainWindowViewModel(Dispatcher dispatcher)
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
this._UIDispatcher = dispatcher;
}
I am taking the View’s dispatcher as a reference (It is not a good practice though as it makes Unit testing difficult. Gary Hall suggested a nice approach using AOP. I can change that later anytime though.). And then this method that I call via a command
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
//_backgroundWorker.RunWorkerAsync();
this._thread = new Thread(new ThreadStart(AddNumbersToList));
this._thread.IsBackground = true;
this._thread.Start();
}
private void AddNumbersToList()
{
Action delAddNum = new Action(AddNumbersToList);
for (int i = 0; i < 100000000; i++)
{
if (null != this._UIDispatcher &&
!this._UIDispatcher.CheckAccess())
_UIDispatcher.Invoke(DispatcherPriority.Render,delAddNum);
else
{
this.ListOfStrings.Add(Convert.ToString(i.ToString()));
}
}
}
The ObservableCollection is bound to a listbox in the View.
The effect that I expected was, as the ObservableCollection gets new numbers added, They should be displayed in the UI. The UI would be nicley responsive too. But strangely the UI is unresponsive. The same thing when I am trying to achieve via a background worker is finely achieved. Can someone please point where am I going wrong. I don’t want to go for the background worker as I want the flexibility of using the more granular Thread class.
Below is the code that I am using with BGWorker and it is running fine:
private BackgroundWorker _backgroundWorker = new BackgroundWorker();
The CTOR:
public MainWindowViewModel()
{
this.ListOfStrings = new ObservableCollection<string>();
this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
_backgroundWorker.DoWork += AddNumbersToList;
_backgroundWorker.RunWorkerCompleted += this.LoadResultsCompleted;
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
}
The methods:
private void AsyncCall()
{
if (this.ListOfStrings.Count > 0)
this.ListOfStrings.Clear();
this._backgroundWorker.RunWorkerAsync();
}
private void AddNumbersToList(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
if(null!=bw)
for (int i = 0; i < 10; i++)
{
bw.ReportProgress(0, i);
Thread.Sleep(1000);
}
}
private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
this.ListOfStrings.Add("Completed");
CommandManager.InvalidateRequerySuggested();
}
}
//This works just wonderful:
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ListOfStrings.Add(Convert.ToString(e.UserState.ToString()));
}
Thank you in advance.
..James
Its the recursion that is hanging your code…
This works for me…