簡體   English   中英

在一種情況下沒有執行 Dispatcher.BeginInvoke

[英]Dispatcher.BeginInvoke not being executed in one case

我正在嘗試修復現有應用程序中的錯誤,在這種情況下,未執行分派事件。

在我們的應用程序中,有幾個服務實現了一個公共抽象類 (AbstractService)。 當服務保存實體並且必須在 UI 線程中發出通知時,就會出現我遇到的問題。

AbstractService的相關部分:

public abstract class AbstractService<TEntity, TData, TInfo> : IDataProvider, IAbstractService
    where TEntity : AbstractEntity, new()
    where TData : AbstractData<TEntity>
    where TInfo : IEntityInfo {

    [...]

    protected virtual void NotifyEntityChanged(NotifyEventItem<TInfo>[] pNotifyEventItems) { }

    private void NotifyPersPlanChanged() {
        if (PersPlanChanged != null)
            PersPlanChanged(this, new NotifyEventArgs<IEntityInfo>(null, PersistanceState.Reset));

        Debug.WriteLine(string.Format("{0} {1} Call {2} to NotifyPersPlanChanged",
            DateTime.Now.ToLongTimeString(), GetType().Name, m_counterNotifyPersPlanChanged++));
    }

    private static int m_counterInternalFireNotification;
    private void InternalFireNotification(List<NotifyEventItem<TInfo>> pNotifyEventItem) {
        if (pNotifyEventItem == null || pNotifyEventItem.Count == 0)
            return;

        Debug.WriteLine(string.Format("{0} {1} Call {2} to InternalFireNotification",
            DateTime.Now.ToLongTimeString(), GetType().Name, m_counterInternalFireNotification++));

        // do not call the event handlers directly, because a transaction may be in progress and
        // we want the event handlers to see the end results of the modifications.
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandleEntityChanged(NotifyEntityChanged), pNotifyEventItem.ToArray());
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandlePersPlanChanged(NotifyPersPlanChanged));
    }
}

每次通過服務修改實體的屬性時, NotifyEntityChanged調用NotifyEntityChanged

以下是 ~20 中AbstractService兩個實現。 第一個,是我遇到的問題,第二個作品。 我將進一步描述問題所在。

public class ErgaenzungsfeldService : AbstractServiceBasic<ErgaenzungsfeldEntity, ErgaenzungsfeldData>, IErgaenzungsfeldService {

    [...]

    [EventPublication(Constants.TopicErgaenzungsfeldChanged, PublicationScope.Global)]
    public event EventHandler ErgaenzungsfeldChanged;

    private static int m_counterNotifyEntityChanged;
    protected override void NotifyEntityChanged(NotifyEventItem<IEntityInfoBasic>[] pNotifyEventItems) {
        Debug.WriteLine(string.Format("{0} {1} Call {2} to NotifyEntityChanged",
            DateTime.Now.ToLongTimeString(), GetType().Name, m_counterNotifyEntityChanged++));

        base.NotifyEntityChanged(pNotifyEventItems);
        if (ErgaenzungsfeldChanged != null) {
            ErgaenzungsfeldChanged(this, new NotifyEventArgs<IEntityInfoBasic>(pNotifyEventItems));
        }
    }
}

public class DienstleistenderService : AbstractAdaLanguageDependentServiceVersion<DienstleistenderEntity, DienstleistenderData>, IDienstleistenderService {

    [...]

    [EventPublication(Constants.TopicDienstleistenderChanged, PublicationScope.Global)]
    public event EventHandler DienstleistenderChanged;

    private static int m_counterNotifyEntityChanged;
    protected override void NotifyEntityChanged(NotifyEventItem<IEntityInfoVersion>[] pNotifyEventItem) {
        Debug.WriteLine(string.Format("{0} {1} Call {2} to NotifyEntityChanged",
            DateTime.Now.ToLongTimeString(), GetType().Name, m_counterNotifyEntityChanged++));
        if (DienstleistenderChanged != null) {
            DienstleistenderChanged(this, new NotifyEventArgs<IEntityInfoVersion>(pNotifyEventItem));
        }
    } 
 }

所有服務都像這樣實例化:

WorkItem.RootWorkItem.Services.AddNew<ErgaenzungsfeldService, IErgaenzungsfeldService>();
WorkItem.RootWorkItem.Services.AddNew<DienstleistenderService, IDienstleistenderService>();

並使用以下兩種方式之一訪問:

WorkItem.Services.Get<IDienstleistenderService>()

[ServiceDependency]
public IErgaenzungsfeldService ErgaenzungsfeldService { get; set; }

問題:並不總是調用 ErgaenzungsfeldService.NotifyEntityChanged。 這僅在導入數據時發生,而不是在“正常”使用應用程序時發生。 通常我的意思是可以在應用程序中修改和保存 ErgaenzungsfeldEntity。 同樣的機制正在使用和工作。

一些觀察:

  • 導入過程是單線程的。 它不在 UI 線程中運行。
  • DienstleistenderService.NotifyEntityChanged 被正確調用,當 ErgaenzungsfeldService.NotifyEntityChanged 不是
  • Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandleEntityChanged(NotifyEntityChanged), pNotifyEventItem.ToArray()) NotifyEntityChanged(pNotifyEventItem.ToArray())System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandlePersPlanChanged(NotifyPersPlanChanged)); 正確調用 ErgaenzungsfeldService.NotifyEntityChanged。 當 UI 收到另一個線程的通知時,應用程序顯然會在稍后拋出異常。
  • 如果通過 UI 保存 ErgaenzungsfeldEntity,則正確調用 ErgaenzungsfeldService.NotifyEntityChanged。

這是出於調試目的添加到幫助我分析問題的不同方法的消息的輸出。

09:39:44 ErgaenzungsfeldService Call 0 to InternalFireNotification
09:39:44 ErgaenzungsfeldService Call 1 to InternalFireNotification
09:39:44 ErgaenzungsfeldService Call 2 to InternalFireNotification
09:39:44 ErgaenzungsfeldService Call 3 to InternalFireNotification
09:40:08 DienstleistenderService Call 0 to InternalFireNotification
09:40:08 DienstleistenderService Call 1 to InternalFireNotification
09:40:09 DienstleistenderService Call 2 to InternalFireNotification
[...]
09:40:14 DienstleistenderService Call 652 to InternalFireNotification
09:40:14 DienstleistenderService Call 653 to InternalFireNotification
09:40:14 DienstleistenderService Call 654 to InternalFireNotification
09:40:14 DienstleistenderService Call 655 to InternalFireNotification
09:40:14 AdaService Call 0 to InternalFireNotification
09:40:14 DienstleistenderService Call 656 to InternalFireNotification
09:40:14 DienstleistungService Call 0 to InternalFireNotification
09:40:14 AufbauorganisationService Call 0 to InternalFireNotification
09:40:14 AufbauorganisationService Call 1 to InternalFireNotification
09:40:14 AdaService Call 0 to NotifyPersPlanChanged
09:40:14 DienstleistenderService Call 0 to NotifyEntityChanged
09:40:16 DienstleistenderService Call 0 to NotifyPersPlanChanged
09:40:16 DienstleistungService Call 0 to NotifyPersPlanChanged
09:40:16 AufbauorganisationService Call 0 to NotifyPersPlanChanged
09:40:16 AufbauorganisationService Call 1 to NotifyPersPlanChanged

問題:什么可能導致通知沒有按照描述執行?

[編輯]通過存儲DispatcherOperation我獲得了更多見解:

private List<DispatcherOperation> m_dispatcherOperationresults = new List<DispatcherOperation>();
private void InternalFireNotification(List<NotifyEventItem<TInfo>> pNotifyEventItem) {
   if (pNotifyEventItem == null || pNotifyEventItem.Count == 0)
      return;

   m_log.DebugFormat("InternalFireNotification called for {0}. TInfo type is {1}", GetType(), typeof(TInfo));

   // do not call the event handlers directly, because a transaction may be in progress and
   // we want the event handlers to see the end results of the modifications.
   DispatcherOperation result = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Send, new HandleEntityChanged(NotifyEntityChanged), pNotifyEventItem.ToArray());
   m_dispatcherOperationresults.Add(result);
   Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandlePersPlanChanged(NotifyPersPlanChanged));
}

這清楚地表明委托執行被卡在執行隊列中。 無論 DispatcherPriority 是設置為 ApplicationIdle(一如既往)還是 Send(最高優先級),它們都會被 ErgaenzungsfeldService 卡住。

在此打印屏幕中,項目 0-3 已在導入期間從非 UI 線程觸發並保持掛起,而項目 4 已從 GUI 線程(幾分鍾后)觸發並執行調度員優先結果

問題:那些代表在某些課程中保持待定狀態,而他們在其他課程中工作的原因可能是什么?

只是為了讓我的評論“正式”。 這可能是由於從另一個線程調用 Dispatcher.CurrentDispatcher 引起的。 這可能會導致應用程序創建一個對 UI 沒有任何訪問權限的新調度程序。

假設您正在從 UI 創建 ErgaenzungsfeldService 類,您可以創建一個具有 Dispatcher.CurrentDispatcher 值的只讀 Dispatcher 字段。 這將為您提供 UI 調度程序。

暫無
暫無

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

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