C# WPF界面在UI线程更新数据时崩溃了。

3

当在UI线程更新数据时,界面会卡顿3-10秒,我希望在不卡顿的情况下在UI线程中更新数据。

代码:

Task t = Task.Factory.StartNew(() =>
{
    // Get data from Server
    GetData(true);
});

Getdata()函数内部
//Converst JSON to DataSet Object:- "tempDataSet"
Task task = Task.Factory.StartNew(() =>
{             
    RetriveData(tempDataSet, firstTime);
}, CancellationToken.None, TaskCreationOptions.None, MainFrame.Current);

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

什么是在UI线程中更新UI的最佳方法,不会出现挂起或冻结的情况?

你为什么要在Getdata()函数内部启动一个新任务?请发布完整的代码。 - mm8
在RetriveData函数内部,有一些UI操作,我使用了新任务来更新UI。 - Ankur Tripathi
在GetData函数内,首先我向服务器发送请求并获取数据。接着将JSON格式的数据转换成DATASET类型,然后调用"RetriveData"方法,在该方法内更新我的observationcollection变量。 - Ankur Tripathi
MainFrame.Current是什么? - Evk
抱歉,我不明白...任务t完成后,我该如何获取数据?我应该在GetData中使用事件吗? - Ankur Tripathi
显示剩余8条评论
2个回答

4

GetData方法不应访问任何UI元素。它应在后台线程上执行,并返回您想要在视图中显示的对象列表。然后,您可以使用ContinueWith方法在UI线程上使用这些对象来填充ObservableCollection,例如:

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

0

使用async/await也可以达到相同的结果,在完成任务后将恢复UI上下文:

// 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);
    }
}

正如您所看到的,我在这里直接调用了RetriveData。您也可以将其标记为async,这样您就可以执行以下操作:

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

为了实现这个,您需要将该方法标记为 async。 如果它是一个事件处理程序,您可以使用 async void,否则请使用 async Task

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接