【问题标题】:Make form elements wait until async / await finishes让表单元素等到异步/等待完成
【发布时间】:2012-12-03 07:11:38
【问题描述】:

我有一个简单的应用程序,它使用 async / await(带有异步目标包的 .NET 4.0)与数据库通信并返回结果。

在数据可用之前,我需要更改某些表单元素的行为。对于简单的实现,我想禁用表单元素,直到数据可用。或者改变表单元素上点击事件的行为。

正确的做法是什么?

我想过

  • 有一些布尔属性让元素知道线程正在运行。
  • 使用事件表单来工作的按钮? (我怀疑这是解决方案,但请详细说明如何)

谢谢。

【问题讨论】:

  • 哪些行为必须改变,如何改变?
  • @RoyDictus:更新了问题
  • @L.B:我希望我的表单可以用于某些元素。
  • 您希望它们开始禁用,还是响应某些用户输入?您的数据源公开了哪些 API?
  • @JonSkeet:我按下了一个进行数据访问调用的按钮,并且我正在使用 async / await (正如您在另一个线程中指出的那样)。发生这种情况时,我需要禁用 10-20 个表单元素。我不想相信我需要使用布尔属性来做到这一点......我认为观察者模式(或类似的东西)是合适的......

标签: c# .net winforms multithreading design-patterns


【解决方案1】:

这应该和我们在您的其他问题中看到的代码一样简单。逻辑上你想要:

foo.Enabled = false;
bar.Enabled = false;
// etc
await Task.Run(...);
foo.Enabled = true;
bar.Enabled = true;

现在,如果您将需要这种处理的所有控件放在一起,则可以使这变得更简单:

SetEnabled(controlCollection, false);
await Task.Run(...);
SetEnabled(controlCollection, true);

...

private static void SetEnabled(IEnumerable<Control> controls, bool enabled)
{
    foreach (var control in controls)
    {
        control.Enabled = enabled;
    }
}

【讨论】:

  • 对于简单的禁用这是要走的路。我只是不知道即使是这样简单的事情的最佳实践是否是使用观察者模式,正如安德斯提议的那样......
  • 嗯,采用设计模式解决方案的原因通常是它们的属性是已知的。在这种情况下:观察者可以很好地适应手头的任务。如果您添加了一种新类型的表单元素,您唯一需要添加任何内容的地方是它的本地代码,而不是用于调度数据库查找的代码。但是可以肯定的是,如果您只有两个字段,请继续执行 :) 但是您确实标记了您的问题“设计模式”:D
【解决方案2】:

要走的路是某种观察者模式。这是最通用的解决方案。

所以:

public interface ObserveDataAvailable {
  public void dataIsAvailable(final Data data);
}

public class ObserveDataAvailableComposite {
  private final List<ObserveDataAvailable> items = new LinkedList<ObserveDataAvailable>();

  public add(final ObserveDataAvailable item) {
    items.add(item);
  }

  public add(final List<ObserveDataAvailable> items) {
    this.items.addAll(items);
  }


  public void dataIsAvailable(final Data data) {
    for (final ObserveDataAvailable item : items) {
      item.dataIsAvailable(item);
    }
  }
}

public class ActivateFormelementWhenDataAvailable {
  private final FormElement fe;

  public ActivateFormelementWhenDataAvailable(final FormElement fe) {
    this.fe = fe;
  }

  public void dataIsAvailable(final Data data) {
    fe.set(data);
    fe.activate();
  }
}


// Run in thread
private void doDataLookup(final ObserveDataAvailable onCompletion) {
  final Data data = getDataFromDb();
  onCOmpletion.dataIsAvailable(data);
}

现在你可以这样做了:

final ObserveDataAvailable onCompletion = new ObserveDataAvailable();
<add the form elements>
runInThread(doDataLookup(onCompletion);

【讨论】:

    猜你喜欢
    • 2019-05-31
    • 2020-10-04
    • 2023-03-16
    • 2019-06-16
    • 2018-03-05
    • 2013-08-19
    • 1970-01-01
    • 2013-06-09
    • 2014-04-03
    相关资源
    最近更新 更多