Ankur Tripathi
Ankur Tripathi

Reputation: 691

c# WPF UI hangs while Update data in UI thread

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?

Upvotes: 3

Views: 2022

Answers (2)

VMAtm
VMAtm

Reputation: 28345

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.

Upvotes: 0

mm8
mm8

Reputation: 169160

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

Upvotes: 4

Related Questions