I have an example here that replicates what I am trying to accomplish.
As the following code will show – I have ViewModel that updates a ObservableCollection Property bound to a View. Normally I would update the collection from a result retrieved from a Model, but hopefully this example will suffice.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Controls;
namespace MVVMWpf.ViewModel
{
public class ListViewModel
{
public ObservableCollection<int> SomeObjectCollection { get; set; }
public ListViewModel()
{
SomeObjectCollection = new ObservableCollection<int>();
}
public void Do()
{
for (int i = 1; i < 1000000; i++)
{
int i1 = i;
SomeObjectCollection.Add(i1);
}
}
}
}
Unfortunately, this blocks this UI. It will only update the View when loop runs to completion. The way I solved it breaks MVVM concepts. That’s why I need your help. I did it this way.
public class ListViewModel
{
private delegate void LongRunningProcess();
public ObservableCollection<int> SomeObjectCollection { get; set; }
private ListBox listBox;
public ListViewModel(ListBox listBox)
{
this.listBox = listBox;
SomeObjectCollection = new ObservableCollection<int>();
}
public void Do()
{
Thread thread = new Thread(() =>
{
for (int i = 1; i < int.MaxValue; i++)
{
int i1 = i;
listBox.Dispatcher.Invoke(
new LongRunningProcess(() =>
SomeObjectCollection.Add(i1);
}});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
As you can see the ViewModel now knows about the listBox element from the UI. And looking at the MVVM diagram only the View should have a reference to the ViewModel through binding. How does one overcome this issue?
Thanks.
You need to let your loop unleash updates to the screen – some kind of DoEvents() will do:
Add it and call that from within your loop.
Using timer as another option, your code should look somthing like that:
in your ctor:
in your timer elpased: