3

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

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

给出了这个例外:ExecuteNonQuery 需要一个开放且可用的连接。连接的当前状态为关闭。

我猜这是因为查询在不同的线程上运行并且不知道打开的连接。

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

谢谢

4

2 回答 2

7

您必须在任务正文中创建并打开此命令的连接。要么不关闭任务外部的连接,我假设这是你在这里所做的,但不能从你粘贴的一行代码中看出。

我会亲自在任务正文中完成所有操作。如果他们不需要,为什么用户必须等待您甚至获得连接/命令设置?此外,您的连接有可能是一个共享实例,并且不能跨线程工作。

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

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

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

这里的神奇之处在于使用TaskScheduler::FromCurrentSynchronizationContext将安排在当前调用的 Dispatcher 线程上执行的延续的方法。

于 2011-05-31T14:35:26.183 回答
1

除了@Drew Marsh的回答,

为避免异常:

当前的 SynchronizationContext 不能用作 TaskScheduler

您可以使用检查同步内容是否存在:

private static TaskScheduler GetSyncronizationContent() => 
     SynchronizationContext.Current != null ? 
          TaskScheduler.FromCurrentSynchronizationContext() : 
          TaskScheduler.Current;

并改用它:

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

backgroundDBTask.ContinueWith((t) =>
{
    //... UI update work here ...
},
GetSyncronizationContent());
于 2016-06-20T11:20:43.333 回答