WPF、MVVM和异步工作

4
我知道这个问题之前已经在这里问过了,但是我已经阅读了几个答案,没有帮助到我。
我有一个ComboBox需要从数据库中获取与所选内容相关的一些信息(可能在失去焦点时,以防止在滚动期间进行数千次调用)。这些信息仅用于显示,不是关键性的,因此在后台线程/任务中获取听起来是完美的解决方案。然而,这确实需要几秒钟的时间,因为它正在从一些非常大的表格中获取计数。用户应该可以自由地转移到其他任务,因为这些信息只是用于显示/参考。 这个问题 倡导使用Background worker,但是这个解决方案有两个问题。1)当worker已经运行时更改选择会引入问题。您可以不启动第二次,这意味着当它返回时,它不再显示新选择的有效信息,或者尝试取消它(这并不总是有效)。2)由于某种无法解释的原因,实际访问后台工作者数据库的方法如果在Model中比在ViewModel中慢返回得更慢,我认为它不属于ViewModel。我真的不知道为什么。

这个问题有几个投票,但OP的问题措辞非常糟糕,而且所选答案只是说“是的,应该可以工作”。

这个问题的方法看起来很有前途,但链接的视频长达一小时(我看了整个视频),并且仅在10-15秒钟内涉及调度程序而没有解释。如果有人有一个更深入地介绍这种方法的文章链接,那就好了。

线程池,如此处建议,看起来可能是最好的选择,因为多个查找请求只会排队,而不会导致已经运行的错误。然而,它没有解释如何使用线程池,而是链接到MSDN文章。如果有人有一个更深入地介绍这种方法的文章链接,那就理想了,因为它似乎是更好的解决方案(当然,我可能是错的)。

我真的尽力研究了这个问题,但大多数答案只是告诉你要使用哪种方法,而不是如何使用它。我真的在寻找一个“如何做”的答案。


你想要异步地做什么呢? 1)加载并填充下拉框项目? 2)当用户选择一个项目时执行其他操作?为了清晰明了,你应该从问题中删除其他内容,并详细阐述你的实际问题。 - Wallstreet Programmer
我认为这很明确。我不需要填充下拉框,我需要从数据库中获取与所选内容相关的信息,并在用户界面上显示此信息。我的问题是,在stackoverflow上有几个解决方案被提出作为答案,但没有解释。如果我删除问题的这部分内容,我担心我会得到链接到那些答案,或类似简略回答。 - Kyeotic
2个回答

6

好的,您的问题:

  1. 您有一个带有项目列表的选择控件
  2. 您有一个昂贵的操作,从当前选定的项目返回一些结果(请注意,此操作应该是昂贵的,不仅需要时间来返回,还需要让您担心同时拥有太多这样的操作)--因此您需要并行执行它
  3. 返回的结果不会被采取任何行动,只会被显示--因此请异步执行它
  4. 如果当前选定的项目更改,则不再需要先前的结果--并且应尽快取消之前的请求,因为它们是昂贵的

使用最新的.NET技术,您应该做什么:

  1. 使用反应式扩展(Rx),设置节流器,以便仅在用户保持当前选择至少500毫秒时触发它(当用户一直按下向下箭头键时,您不想产生许多任务)
  2. 当节流器触发时,调用一个异步方法(Async CTP),它在一个任务中等待操作(长时间运行以避免饥饿线程池),并放入取消标记;保存当前选择以供稍后比较
  3. 当操作返回时,将结果设置到您的数据上下文中(您的显示控件应该绑定到它)--异步方法始终在UI线程上继续,因此您不必担心线程访问
  4. 如果节流器触发并且存在未完成的任务/取消标记,请先使用取消标记取消任务,然后根据#2生成新任务。等待将抛出异常,因为任务已被取消,但这无关紧要,因为您不再需要它。
  5. 这里没有并发问题,因为Async CTP始终在UI线程上继续。就所有操作而言,它们都是单线程的,不会互相干扰。

我认为如果您使用带有Rx的Async CTP,它只需要大约10行代码。

注意:如果您的操作不昂贵,则不必使用取消标记。只需允许任务运行到完成,但忽略结果即可。但是,仍建议您尽早取消数据库查询,尽管它在客户机上不昂贵,但在服务器上却很昂贵。


这听起来很棒,但在我测试之前我无法将其标记为答案,而且由于我不知道如何使用RX或Async CTP,我将不得不在网上搜索教程。如果您有一个链接可能会加速事情。非常感谢您的好答案! - Kyeotic

3
你可以尝试使用异步绑定:
<ComboBox Name="theCombo" ... />
<TextBlock Text="{Binding Path=SomeSlowProperty, ElementName=theCombo, IsAsync=True}" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接