使用TPL时避免窗口(WPF)冻结 [英] Avoiding the window (WPF) to freeze while using TPL

查看:252
本文介绍了使用TPL时避免窗口(WPF)冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个WPF,它具有一个在SQL Server中执行SQL查询的按钮(查询可能需要很长时间才能运行). 我想使用TPL来做到这一点.

I am building a WPF which has a button that execute a sql query in sql server (the query could take a long time to run). I want to use TPL for doing that.

此代码: var result = Task.Factory.StartNew(()=> {command.ExecuteNonQuery();});

This code: var result = Task.Factory.StartNew(() => { command.ExecuteNonQuery(); });

给出以下异常: ExecuteNonQuery需要一个开放且可用的连接.连接的当前状态为关闭.

gives this exception: ExecuteNonQuery requires an open and available Connection. The connection's current state is closed.

我猜这是由于查询在不同的线程上运行并且不知道打开的连接这一事实造成的.

I guess this is due to the fact that the query runs on a different thread and is not aware of the open connection.

我有2个问题: 1.如何使新线程知道此打开的连接? 2.解决此问题后,如何使该窗口不因该查询而冻结.

I have 2 questions: 1. How do I make the new thread know of this open connection? 2. After solving this ,How do I get the window not to freeze due to this query.

谢谢

推荐答案

您将必须在Task的主体中创建并打开此命令的连接.要么要么不关闭Task外部的连接,我假设这就是您在此处所做的事情,但是无法从粘贴的一行代码中看出来.

You will have to create and open the connection for this command within the Task's body. Either that or don't close the connection outside the Task, which I assume is what you're doing here, but can't tell from the one line of code you pasted.

我个人将全部在Task主体内完成.如果不需要,用户为什么还要等您才能获得连接/命令设置?另外,您的连接有可能是一个共享实例,并且无法跨线程工作.

I would personally do it all inside the Task body. Why should the user have to wait for you to even get the connection/command setup if they don't have to? Also there's the chance that you connection is a shared instance and that won't work across threads.

一旦将DB工作放入Task中,它将默认在线程池线程上执行,这将释放WPF调度程序线程以返回到处理UI事件,从而防止冻结".您很可能希望在该数据库任务完成后更新UI,并执行此操作,即会添加一个继续任务,但是为了能够从该继续任务中操作UI,您需要确保已明确将其计划为在Dispatcher线程上运行.这是通过在计划继续时为当前同步上下文显式指定TaskScheduler来完成的.看起来像这样:

Once you get the DB work into a Task it will be executed on a Thread Pool thread by default which will free up the WPF dispatcher thread to go back to processing UI events preventing the "freezing". Most likely you will want to update the UI after that DB task has completed and to do that you would hpjust add a continuation task, but in order to be able to manipulate the UI from that continuation task you need to make sure it's explicitly scheduled to run on the Dispatcher thread. This is done by explicitly specifying a TaskScheduler for the current synchronization context while scheduling the continuation. That would look something like this:

Task backgroundDBTask = Task.Factory.StartNew(() =>
{
    ... DB work here ...
});

backgroundDBTask.ContinueWith((t) =>
{
    ... UI update work here ...
},
TaskScheduler.FromCurrentSynchronizationContext());

这里的妙处在于使用TaskScheduler::FromCurrentSynchronizationContext方法,该方法将安排在当前调用的Dispatcher线程上执行的延续.

The magic here is the use of the TaskScheduler::FromCurrentSynchronizationContext method which will schedule the continuation to be executed on the Dispatcher thread of the current call.

这篇关于使用TPL时避免窗口(WPF)冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆