C# 使用任务但用户界面仍被阻止

C# 使用任务但用户界面仍被阻止,c#,wpf,multithreading,mvvm,C#,Wpf,Multithreading,Mvvm,我有一个WPF MVVM c#应用程序。在我的一个视图中,我必须在单击按钮后从数据库检索数据。 对数据库的调用非常长,因此我希望在调用时启用微调器,并在调用完成时禁用它 因此,在处理按钮单击的方法中(使用命令,而不是代码隐藏),我设置布尔变量以启用微调器,然后创建一个任务,该任务获取数据并将其设置为一个可观察收集,如下所示 private void GetDataButtonCommand() { this.IsBusy = true; var tasks = new List&

我有一个WPF MVVM c#应用程序。在我的一个视图中,我必须在单击按钮后从数据库检索数据。 对数据库的调用非常长,因此我希望在调用时启用微调器,并在调用完成时禁用它

因此,在处理按钮单击的方法中(使用命令,而不是代码隐藏),我设置布尔变量以启用微调器,然后创建一个
任务
,该任务获取数据并将其设置为一个
可观察收集
,如下所示

private void GetDataButtonCommand() {
    this.IsBusy = true;
    var tasks = new List<Task>();

    tasks.Add(Task.Factory.StartNew(() =>
    {
        System.Windows.Application.Current.Dispatcher.BeginInvoke(new System.Action(() =>
        {
            var GotData= DBHelper.GetData();
            _observablecollectionname.Clear();
            foreach (var item in GotData)
            {
                _observablecollectionname.Add(item);
            }
        }));
    }));

    var finalTask = Task.Factory.ContinueWhenAll(tasks.ToArray(), datacomplete =>
    {
        this.IsBusy = false;  
    });
}
private void GetDataButtonCommand(){
this.IsBusy=true;
var tasks=新列表();
tasks.Add(Task.Factory.StartNew(()=>
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(新的System.Action(()=>
{
var GotData=DBHelper.GetData();
_observablecollectionname.Clear();
foreach(GotData中的var项)
{
_observablecollectionname.Add(项);
}
}));
}));
var finalTask=Task.Factory.continuewhell(tasks.ToArray(),datacomplete=>
{
this.IsBusy=false;
});
}
完成
任务后
我想禁用微调器

我遇到的问题是,在调用过程中无法看到微调器。UI仍然被阻止,即使我正在使用
任务执行数据库查询


我做错了什么?

您的代码正在UI thead上运行

您在
System.Windows.Application.Current.Dispatcher.BeginInvoke(new System.Action(()=>{…}))中执行所有操作
,因此自然会阻止UI

您应该只在确实需要执行UI操作时调用dispatcher

Move
var GotData=DBHelper.GetData()在调度程序之前


但是最好使用C#5.0及更高版本的
async
/
wait
模式/关键字

您的代码正在UI thead上运行

您在
System.Windows.Application.Current.Dispatcher.BeginInvoke(new System.Action(()=>{…}))中执行所有操作
,因此自然会阻止UI

您应该只在确实需要执行UI操作时调用dispatcher

Move
var GotData=DBHelper.GetData()在调度程序之前


但是最好使用C#5.0及更高版本的
async
/
wait
模式/关键字

当我有一个长时间运行的查询时,我总是使用下面的代码

    private async void button1_Click(object sender, EventArgs e)
    {
        var list = await GetDatabaseAsync();
        //do whatever you need with the list.
    }



    private async Task<List<string>>  GetDatabaseAsync()
    {
        var list = Task.Run(() =>
        {
            var _observablecollectionname = new List<string>();
            var GotData = Helper.GetData();
            _observablecollectionname.Clear();
            foreach (var item in GotData)
            {
                _observablecollectionname.Add(item);
            }
            return _observablecollectionname;
        });
        return await list;
    }
private async void按钮1\u单击(对象发送方,事件参数e)
{
var list=等待GetDatabaseAsync();
//对清单做你需要的任何事情。
}
专用异步任务GetDatabaseAsync()
{
var list=Task.Run(()=>
{
var_observeCollectionName=新列表();
var GotData=Helper.GetData();
_observablecollectionname.Clear();
foreach(GotData中的var项)
{
_observablecollectionname.Add(项);
}
返回_observeCollectionName;
});
返回等待列表;
}

当我有一个长时间运行的查询时,我总是使用下面的代码

    private async void button1_Click(object sender, EventArgs e)
    {
        var list = await GetDatabaseAsync();
        //do whatever you need with the list.
    }



    private async Task<List<string>>  GetDatabaseAsync()
    {
        var list = Task.Run(() =>
        {
            var _observablecollectionname = new List<string>();
            var GotData = Helper.GetData();
            _observablecollectionname.Clear();
            foreach (var item in GotData)
            {
                _observablecollectionname.Add(item);
            }
            return _observablecollectionname;
        });
        return await list;
    }
private async void按钮1\u单击(对象发送方,事件参数e)
{
var list=等待GetDatabaseAsync();
//对清单做你需要的任何事情。
}
专用异步任务GetDatabaseAsync()
{
var list=Task.Run(()=>
{
var_observeCollectionName=新列表();
var GotData=Helper.GetData();
_observablecollectionname.Clear();
foreach(GotData中的var项)
{
_observablecollectionname.Add(项);
}
返回_observeCollectionName;
});
返回等待列表;
}

Draw。取图纸清单,画2道“UI线”、“其他线”。然后将代码的每一行映射到其中一条车道。。。。如果这还不足以发现问题,它至少应该向您澄清您不知道的事情。这些任务是在后台线程中执行的吗?此代码中没有异步/等待。对我来说,它看起来像是在UI线程上运行的。或者至少没有从后台线程返回的点。
ContinueWith
continuewhere
等同于
wait
调用C#5。0@Tseng又是学到的东西;)画取图纸清单,画2道“UI线”、“其他线”。然后将代码的每一行映射到其中一条车道。。。。如果这还不足以发现问题,它至少应该向您澄清您不知道的事情。这些任务是在后台线程中执行的吗?此代码中没有异步/等待。对我来说,它看起来像是在UI线程上运行的。或者至少没有从后台线程返回的点。
ContinueWith
continuewhere
等同于
wait
调用C#5。0@Tseng又是学到的东西;)这里的主要问题是,您不能从线程操作可观察的集合。必须通过完成,并且您在示例中使用列表。列表可以更改为类似列表的任何列表。这个问题有点模棱两可。如果只有一个列表,上面的代码可以正常工作。但若有多个列表,那个么还有另一种方法。问题是关于WPF和
ObservableCollection
。它不是一个普通的列表或集合,而是一个impements
INotifyCollectionChanged
接口,用于在集合更新时通知WPF UI。并且您只能从UI线程中添加/删除项目。如果试图从非UI线程执行此操作,则会出现异常。看见另一方面,在MVVM中,我们也不注册事件处理程序,但这是另一个故事。这里的主要问题是,您无法从线程操作可观察的集合。必须通过完成,并且您正在使用li