如何在执行后台任务时保持UI响应

时间:2018-11-09 11:18:39

标签: c# wpf

我实现了一个刷新按钮,该按钮读取数据库并检查是否有新条目并将其添加到ObservableCollection中。我有一个刷新图标,刷新图标取决于IsRefreshing的值。像这样:

new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;
            IsRefreshing = true;

            //Reads database
            //ObservableCollection.Add(NewValues)

            IsRefreshing = false;
        }).Start();

但是运行此命令会给我一个例外:

  

这种CollectionView不支持从与Dispatcher线程不同的线程对其SourceCollection进行更改。

我显然会以错误的方式进行操作,但是不确定执行后台任务时如何使UI保持响应状态?

2 个答案:

答案 0 :(得分:2)

您不能从后台线程修改UI。所有受支持的.NET版本都允许使用async/await在后​​台执行某些操作并返回到UI线程。

ADO.NET,实体框架,Dapper和大多数ORM支持异步执行。例如,ADO.NET的ExecuteReader具有等效的ExecuteReaderAsync方法。 EF的ToList()有一个ToListAsync()。 Dapper的QueryQueryAsync

您应该将事件处理程序更改为以下内容:

private async void btn1_Click(object sender, RoutedEventArgs e)
{
    using(var connection = new SqlConnection(_cnString)
    {
        IsRefreshing = true;
        await connection.OpenAsync();
        var results=await connection.QueryAsync<Value>(query);
        //We're now back in the UI thread
        _theCollection.AddRange(results);
        IsRefreshing = false;
    }
}

调用OpenAsyncQueryAsync时,.NET将在后台运行查询并释放当前(UI)线程。查询完成后,await确保将在原始线程(即UI线程)上恢复执行。

答案 1 :(得分:0)

基本上,您必须将此项目添加到集合中,但必须在Dispatcher线程上执行此操作,

Application.Current.Dispatcher.Invoke(() => ObservableCollection.Add(NewValues));