簡體   English   中英

在UI線程上進行大量CPU密集型工作時,如何在C#VSTO外接程序中保持Outlook UI響應

[英]How to keep Outlook UI responsive in C# VSTO addin when making lots of CPU-intensive work on UI thread

我的代碼可以在循環中多次調用Outlook API。 Outlook不喜歡從工作線程訪問其API,因此我必須為此使用主線程。 使用async / await進行網絡查詢的代碼部分非常好,因此UI不會凍結。 但是,當代碼達到CPU密集型部分(調用Outlook API)時,UI顯然會凍結。

我插入了一個await Task.Delay(1) ,它每經過10毫秒await Task.Delay(1)執行一次,但是由於計時器解析度不夠精確(15毫秒),因此它使代碼明顯變慢(盡管取消阻止UI)。

DateTime d1 = DateTime.Now;
int interval = 10;
foreach (SomeItem item in items)
{
    // Intense access to Outlook API...
    // ...

    DateTime d2 = DateTime.Now;
    if (d2.Subtract(d1).TotalMilliseconds > interval)
    {
        await Task.Delay(1);
        d1 = d2;
    }
}

使用Task.Yield代替Task.Delay(1)不會取消阻止UI(MSDN始終不建議為此使用Task.Yield)。

interval從10ms增加到更大的值(100ms)可以將性能損失降至最低,並使UI有所響應,但不那么平滑。

也許有更好的選擇,這並不意味着在UI平滑度和性能之間進行權衡? 也許像一個很好的舊Application.DoEvents但是采用一種現代且推薦的方式?

單獨使用OOM並沒有做到這一點的好方法。 擴展MAPI是線程安全的,但是只能從C ++或Delphi訪問。 您可以使用Redemption (任何語言)-其RDO對象系列完全基於MAPI,可以在輔助線程中使用。 Application.Session.MAPIOBJECT保存到主線程上的專用變量中(這樣,只需要整理該變量)。 在輔助線程上,創建RDOSession對象的實例(這樣,將在該線程上初始化MAPI系統),並將其MAPIOBJECT屬性設置為保存在主線程上的variabel。 這樣,兩者將共享相同的MAPI會話。 然后,您可以使用RDOSession.GetFolderFromID / GetDefaultFolder / etc檢索文件夾。 並處理這些物品。

您可能知道不能在輔助線程中使用OOM,否則您可能會在代碼中得到異常。 最新版本的Outlook
檢測此類用例並可能引發異常。 但是,您可以自由使用Outlook所基於的低級API-擴展MAPI或圍繞該API的任何其他包裝,例如“兌換”。

請注意,如果僅處理Exchange配置文件,則可以考慮使用EWS或Outlook API在輔助線程上獲取所需的數據。 有關更多信息請參見Exchange中的EWS托管API,EWS和Web服務

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM