Reputation: 3462
Every time when timer invoke UpdateDocumentsListFromServer
UI freezes for 3 seconds. How to update list in async style under .net 3.5?
ViewModel:
public class ShippingDocumentsRegisterViewModel : ViewModelBase
{
ShippingDocumentsModel model = new ShippingDocumentsModel();
DispatcherTimer timer = new DispatcherTimer();
BackgroundWorker BW = new BackgroundWorker();
public ShippingDocumentsRegisterViewModel()
{
timer = new DispatcherTimer();
timer.Tick += new EventHandler(UpdateDocumentsListFromServer);
timer.Interval = new TimeSpan(0, 0, 10);
timer.Start();
this.Columns = model.InitializeColumns();
BW.DoWork += UpdateDocumentsList;
BW.RunWorkerAsync();
}
public void UpdateDocumentsList(object o, EventArgs args)
{
this.ShippingDocuments = model.GetDocuments();
}
public void UpdateDocumentsListFromServer(object o, EventArgs args)
{
// Taking a lot of time. How to do it async?
var tempDocuments = model.GetDocumentsFromServer();
foreach (var item in tempDocuments)
{
this.shippingDocuments.Add(item);
}
//
}
private ObservableCollection<ShippingDocument> shippingDocuments;
public ObservableCollection<ShippingDocument> ShippingDocuments
{
get
{
return shippingDocuments;
}
private set
{
shippingDocuments = value;
RaisePropertyChanged("ShippingDocuments");
}
}
public ObservableCollection<ShippingDocumentColumDescriptor> Columns { get; private set; }
}
GetDocumentsFromServer look like
public ObservableCollection<ShippingDocument> GetDocumentsFromServer()
{
System.Threading.Thread.Sleep(3000);
return new ObservableCollection<ShippingDocument> { new ShippingDocument { Name = "Test" } };
}
Upvotes: 2
Views: 8346
Reputation: 7193
Just offload it to a new thread using Task and Async/Await like so:
public async void UpdateDocumentsListFromServer(object o, EventArgs args)
{
// This will execute async and return when complete
await Task.Run(()=>{
var tempDocuments = model.GetDocumentsFromServer();
foreach (var item in tempDocuments)
{
this.shippingDocuments.Add(item);
}
});
//
}
Keep in mind this updates on a different thread then the UI. So it is not allowed to touch anything on the UI thread or you will get threading issues. So if shippingDocuments was created on the UI thread and is not thread-safe you could instead return a collection of items then add them:
public async void UpdateDocumentsListFromServer(object o, EventArgs args)
{
// Execute on background thread and put results into items
var items = await Task.Run(()=>{
var tempDocuments = model.GetDocumentsFromServer();
return tempDocuments;
});
//add occurs on UI thread.
this.shippingDocuments.AddRange(tempDocuments);
}
Upvotes: 2
Reputation:
You could also use a background worker that reports progress to the UI
public ShippingDocumentsRegisterViewModel()
{
BW.DoWork += UpdateDocumentsListFromServer;
BW.RunWorkerCompleted += BW_RunWorkerCompleted;
BW.WorkerReportsProgress = true;
BW.ProgressChanged += UpdateGui;
BW.RunWorkerAsync();
}
public void UpdateGui(object o, EventArgs args)
{
foreach (var item in tempDocuments)
{
this.shippingDocuments.Add(item);
}
}
public void UpdateDocumentsListFromServer(object o, EventArgs args)
{
while (true) {
System.Threading.Thread.Sleep(3000);
tempDocuments = GetDocumentsFromServer();
BW.ReportProgress(0);
}
}
int num = 0;
public ShippingDocument[] GetDocumentsFromServer()
{
System.Threading.Thread.Sleep(3000);
return new ShippingDocument[1] { new ShippingDocument { Name = "Test" + num++} };
}
private ShippingDocument[] tempDocuments = new ShippingDocument[0];
Upvotes: 2
Reputation: 2842
As mentioned in comment, you can make use of Timers instead of DispatcherTimer
. DispactherTimer
will access the UIThread where as Timer use different thread from threadpool.
Also, you can dispatch an action to UIThread from different thread
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
//Do some UI stuffs
}));
Hope that helps.
Upvotes: 0
Reputation: 185553
Use a regular Timer
and only dispatch the access to shippingDocuments
.
Upvotes: 0