【问题标题】:How to load DrawingVisuals asynchronously with Async and Await?如何使用 Async 和 Await 异步加载 DrawingVisuals?
【发布时间】:2016-09-03 05:04:34
【问题描述】:

我使用 Canvas 作为数千个 DrawingVisuals 的宿主。加载速度非常慢。我尝试仅加载开始时可见的 DrawingVisuals 并异步加载并等待其他 DrawingVisuals:

Async Sub AddVisuals()
    Dim visuals = Await Task.Run(AddressOf CreateVisuals)
    For Each vis In visuals
        AddVisualChild(vis)
        AddLogicalChild(vis)
    Next
End Sub
Function CreateVisuals() As DrawingVisual()
    ....
End Function

但是 Task.Run 调用另一个线程。所以我得到一个 InvalidOperation 异常,指出该对象由另一个线程拥有。 但是here我发现:

async 和 await 关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不在其自己的线程上运行。该方法在当前同步上下文上运行,并且仅在该方法处于活动状态时才使用线程上的时间。您可以使用 Task.Run 将 CPU 密集型工作转移到后台线程,但后台线程对等待结果可用的进程没有帮助。

那么,有没有办法通过 async 和 await 添加 DispatcherObject(这里:DrawingVisual)?

【问题讨论】:

  • 当我使用 Visual Studio 2010 时,我没有使用过 async/await,但Dim visuals = Await CreateVisuals() 不会解决问题吗?或者只是 Dim visuals = CreateVisuals() 因为 CreateVisuals() 应该阻塞当前线程直到它返回。
  • 但我不想阻塞当前线程。绘制所有视觉效果需要太长时间并且会阻塞 UI。
  • 那你为什么用Await
  • 我希望当前不可见的 DrawingVisuals - 稍后它们可以通过滚动变得可见 - 在后台加载而不阻塞 UI。
  • 那么您必须首先删除该函数并循环创建它们的代码。在该代码的末尾,在它开始创建下一个视觉对象之前,您调用 AddVisualChild()AddLogicalChild()

标签: vb.net multithreading asynchronous async-await


【解决方案1】:

我找到了解决方案:visual.Dispatcher.InvokeAsync(Sub() DrawVisual) 是 Awaitable。所以我将它与 Await 一起使用。 (在DrawVisual RenderOpen 中被调用)现在所有的DrawingVisuals 都加载得更快并且UI 不再被阻塞。感谢 Visual Vincent 和 Scott 的帖子。

【讨论】:

    【解决方案2】:

    为了实现您的“我希望当前不可见的 DrawingVisuals - 稍后它们可以通过滚动变得可见 - 在后台加载而不阻塞 UI”的目标,我建议您尝试使用 UI 虚拟化而不是异步...等待.

    将容器控件的 IsItemsHost 属性设置为 True,然后可以将 ItemsPanel 属性设置为 VirtualizingStackPanel 并将 IsVirtualizing 设置为 true。

    阅读更多https://msdn.microsoft.com/en-us/library/cc716879(v=vs.100).aspx

    【讨论】:

    • 这个我试过了,但是visula.RenderOpen中的绘图太慢了,没有平滑滚动。但我找到了解决方案。看看我下面的答案。
    猜你喜欢
    • 2019-01-17
    • 1970-01-01
    • 2013-04-11
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2017-09-17
    • 1970-01-01
    相关资源
    最近更新 更多