3

UI freeze for 3-10 seconds while update data in UI thread I want to update data in UI thread without freeze.

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 UI in UI thread without hangs or freeze?

13
  • Why are you starting a new task inside Getdata()? Please post the full code. Commented Apr 24, 2017 at 9:55
  • inside RetriveData there are UI operations that by i used new task for UI update Commented Apr 24, 2017 at 9:57
  • Where are there UI operations in GetData? This makes no sense. All UI operations will freeze the UI thread. Commented Apr 24, 2017 at 9:58
  • Inside GetData first i request to server and get data from server.. After this i convert the JSON data to DATASET and after that i call "RetriveData" method and inside "RetriveData" ... i update my observationcollection variable Commented Apr 24, 2017 at 10:02
  • And what is MainFrame.Current? Commented Apr 24, 2017 at 10:03

2 Answers 2

4

The GetData method should not access any UI elements. It should be executed on a background thread and return a list of objects that you want to display in the view. You could then use the ContinueWith method to populate the ObservableCollection with these objects back on the UI thread, e.g.:

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());
Sign up to request clarification or add additional context in comments.

Comments

0

The same result can be achieved with async/await, which will restore the UI context after completing the task:

// 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 call the RetriveData directly here. Also you can mark it as async too, so you can do:

public async Task<> GetData(...)
{
    // some code ...
    return await Task.Run(() => 
    {
        return RetriveData(tempDataSet, firstTime));
    }
}

To achieve this you need to mark the method as async. If it is a event handler, you can use async void, in other case use async Task.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.