C # WPF UI hangs when updating data on the UI thread
User interface termination within 3-10 seconds when data is refreshed on the user interface thread. I want to update data on the UI thread without hanging.
code:
Task t = Task.Factory.StartNew(() =>
{
// Get data from Server
GetData(true);
});
Inside Getdata()
//Converst JSON to DataSet Object:- "tempDataSet"
Task task = Task.Factory.StartNew(() =>
{
RetriveData(tempDataSet, firstTime);
}, CancellationToken.None, TaskCreationOptions.None, MainFrame.Current);
Inside RetriveData
DataTable response = tempDataSet.Tables["response"];
DataTable conversations = tempDataSet.Tables["convo"];
foreach (DataRow row in conversations.Rows) // UI Hangs in the method
{
UC_InboxControl control = new UC_InboxControl(row, uC_Inbox);
if (uC_Inbox.mnuUnreadChat.IsChecked == false)
{
inboxControlCollection.Add(control);
}
else
{
inboxUnreadOnlyControlCollection.Add(control);
}
}
What is the best approach to update the UI on the UI thread without hanging or freezing?
source to share
The method GetData
should not have access to UI elements. It should be executed on a background thread and return a list of objects that you want to display in the view. Then you can use a method ContinueWith
to populate ObservableCollection
these objects back on the UI thread, for example:
Task t = Task.Factory.StartNew(() =>
{
return GetData(true); // <-- GetData should return a collection of objects
}).ContinueWith(task =>
{
//that you add to your ObservableCollection here:
foreach (var item in task.Result)
yourObservableCollection.Add(item);
},
System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
source to share
The same result can be achieved with async/await
, which will restore the UI context after the task completes:
// await the task itself, after that do the UI stuff
var collection = await Task.Run(() =>
{
// directly call the retrieve data
return RetriveData(tempDataSet, firstTime);
});
// this code will resume on UI context
foreach (var item in collection)
{
var control = new UC_InboxControl(row, uC_Inbox);
if (!uC_Inbox.mnuUnreadChat.IsChecked)
{
inboxControlCollection.Add(control);
}
else
{
inboxUnreadOnlyControlCollection.Add(control);
}
}
As you can see, I am calling RetriveData
right here. Also you can mark it as async
so you can:
public async Task<> GetData(...)
{
// some code ...
return await Task.Run(() =>
{
return RetriveData(tempDataSet, firstTime));
}
}
To do this, you need to mark the method as async
. If this is an event handler you can use async void
, otherwise use async Task
.
source to share