1

例如,我有一个业务对象Person

class Person : INotifyPropertyChanged
{
    string Name { get; set; }
    DateTime DateOfBirth { get; set; }
}
// ^ abbreviated for better legibility; implementation would be trivial

而且我有一些 Winforms UI 控件数据绑定到此类的对象:

Person somePerson = ...;
nameTextBox.DataBindings.Add("Text", somePerson, "Name");
dobDatePicker.DataBindings.Add("Value", somePerson, "DateOfBirth");

现在我正在进行更改,somePerson并且由于已经INotifyPropertyChanged实施,这些更改会反映在 UI 中。到现在为止还挺好。

现在我的问题:如果我在工作线程中进行更改somePerson(即不在 UI 线程中),例如因为我正在从数据库加载数据作为后台操作,这可能会导致异常,因为数据绑定尝试更新控件,仅允许在 UI 线程上发生。

这意味着我需要调用InvokeRequiredUI 元素来查看是否允许我更新业务对象——这似乎违反了应用程序的逻辑分层

理想情况下,我希望能够修改我的业务对象,而不必关心它是否与 UI 数据绑定。这是否可以通过 Winforms 数据绑定实现?

4

1 回答 1

3

这不能回答你的问题,但我尽量避免这个问题。

由于数据绑定的存在,我确保唯一可以更新业务对象的代码是在 GUI 线程上运行的代码。

对于异步操作,我采用以下模式:

  1. 将工作发送到后台:从 GUI 线程触发异步操作——例如,线程池项。仅将纯数据类型传递到线程池中,并且仅接收纯数据类型返回。如果线程池使用业务对象,请确保这些对象是全新的(尚未绑定数据),或者是原始对象的克隆(以避免并发访问)
  2. 完成工作并获得结果:在后台线程上执行异步操作。后台线程代码将拥有 GUI 给它的“安全”对象;它不会与应用程序的其余部分进行任何交互。
  3. 在 GUI 中解压结果:当异步操作完成时,它会在 GUI 线程上触发“我完成”事件。作为响应,GUI 线程可以从后台操作中解包任何结果并将它们合并回主要业务对象,在知道它不会处理并发访问的情况下是安全的。

我可以推荐System.Threading.Tasks.Task该类作为上述大多数步骤的抽象。它是 .NET 4.0 中的新功能,但也可以单独下载 .NET 3.5 应用程序。

步骤 (1) 和 (2) 是Task该类在没有任何定制的情况下所做的。Task您可以通过从后台线程内部生成一个单独的线程并指定TaskScheduler.FromCurrentSynchronizationContext为调度程序来实现 (3)。(您需要FromCurrentSynchronizationContext在步骤(1)中从 GUI 线程调用,而不是从后台线程调用。)

于 2010-08-01T10:38:00.610 回答