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?

+3


source to share


2 answers


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());

      

+3


source


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

.

0


source







All Articles