我知道以前有人问过这个问题,但是我已经看过了几个没有帮助我的答案。
我有一个ComboBox,需要从数据库中获得一些与选择相关的信息(可能在失去焦点时,在滚动期间停止一千次调用)。此信息仅用于显示,并不重要,因此进入后台线程/任务听起来像是完美的解决方案。但它确实需要几秒钟,因为它从一些非常大的表中获取计数。用户应该可以自由地转移到其他任务,因为这些信息实际上只是用于显示/参考。
这个问题提倡使用后台worker,但是这个解决方案有两个问题。1)在worker已经运行时更改选择会引入问题。您可以不启动它第二次,这意味着当它返回时,它不再显示新选择的有效信息,或尝试取消它(这并不总是工作)。2)由于某种原因,我无法解释,如果方法在模型中,实际访问后台工作人员数据库的方法返回速度比在ViewModel中慢,我认为它不属于。我真不知道为什么。
这个问题有几个投票,但是OP的问题措辞很差,选择的答案只是说"是的,应该工作。"
这个问题的方法看起来很有希望,但是链接的视频长达一个小时(我看了整个视频),并且只涉及调度员10-15秒而没有解释它。如果有人能提供一篇更深入地介绍这种方法的文章的链接,那就太好了。
线程池,正如这里建议的那样,看起来可能是最好的方法,因为查找的多个请求只是排队,而不是导致已经运行的错误。但是,它没有解释如何使用线程池,而是链接到MSDN文章。如果有人有更深入地介绍这种方法的文章的链接,那将是理想的,因为它似乎是更好的解决方案(当然,我可能是错的)。
我真的很努力地在这个问题上做了研究,但是大多数的答案只是告诉你使用什么方法,而不是如何使用它。我真的在寻找一个"如何做"。"
OK。你的问题:
- 你有一个选择控件的项目列表
- 你有一个昂贵的操作,它从当前选择的项目返回一些结果(注意,这个操作应该是昂贵的,不仅仅是需要时间返回,为了让你担心同时没有太多的结果)——所以你需要并行执行
- 返回的结果不被执行,只被显示——所以异步执行
- 如果当前选择的项目发生变化,您不再需要之前的结果—并且之前的请求应尽快取消,因为它们是昂贵的
你应该用最新的。net技术做什么:
- 使用响应扩展(Rx),设置一个油门,使其仅在用户保持当前选择时触发,例如,至少500ms(你不想在用户不断按下箭头键时产生许多许多次)
- 当油门触发时,调用async方法(async CTP),该方法等待任务中的操作(长时间运行以避免耗尽线程池),并放入一个取消令牌;保存当前选择供以后比较
- 当操作返回时,将结果设置到您的数据上下文(您的显示控件应该绑定到该上下文)—异步方法始终在UI线程上继续,因此您不必担心线程访问
- 如果油门触发并且有一个未完成的任务/取消令牌,首先使用取消令牌来取消任务,然后根据#2生成一个新任务。await会抛出,因为Task被取消了,但没关系,因为你不再需要它了。 这里没有并发问题,因为异步CTP总是在UI线程上继续。就你所有的操作而言,它们都是单线程的,不会相互影响。
我认为如果你在Rx中使用异步CTP,它大约是10行代码。
注意:如果你的操作是NOT EXPENSIVE,你不需要使用取消令牌。只允许任务运行到完成,而忽略结果。但是,仍然建议您尽早取消数据库查询,尽管这在客户端机器上并不昂贵,但在服务器上却很昂贵。你可以尝试使用异步绑定:
<ComboBox Name="theCombo" ... />
<TextBlock Text="{Binding Path=SomeSlowProperty, ElementName=theCombo, IsAsync=True}" />