[英]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。 同樣的機制正在使用和工作。
一些觀察:
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 收到另一個線程的通知時,應用程序顯然會在稍后拋出異常。這是出於調試目的添加到幫助我分析問題的不同方法的消息的輸出。
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.