Dispatcher.BeginInvoke在一种情况下没有被执行

我正在尝试修复现有应用程序中的错误,在单个案例中,调度事件未执行。

在我们的应用程序中,有几个服务实现了一个公共抽象类(AbstractService)。 当服务保存实体并且必须在UI线程中引发通知时,我遇到的问题就出现了。

AbstractService的相关部分:

public abstract class AbstractService : IDataProvider, IAbstractService where TEntity : AbstractEntity, new() where TData : AbstractData where TInfo : IEntityInfo { [...] protected virtual void NotifyEntityChanged(NotifyEventItem[] pNotifyEventItems) { } private void NotifyPersPlanChanged() { if (PersPlanChanged != null) PersPlanChanged(this, new NotifyEventArgs(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> 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, IErgaenzungsfeldService { [...] [EventPublication(Constants.TopicErgaenzungsfeldChanged, PublicationScope.Global)] public event EventHandler ErgaenzungsfeldChanged; private static int m_counterNotifyEntityChanged; protected override void NotifyEntityChanged(NotifyEventItem[] 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(pNotifyEventItems)); } } } public class DienstleistenderService : AbstractAdaLanguageDependentServiceVersion, IDienstleistenderService { [...] [EventPublication(Constants.TopicDienstleistenderChanged, PublicationScope.Global)] public event EventHandler DienstleistenderChanged; private static int m_counterNotifyEntityChanged; protected override void NotifyEntityChanged(NotifyEventItem[] 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(pNotifyEventItem)); } } } 

所有服务都实例化如下:

 WorkItem.RootWorkItem.Services.AddNew(); WorkItem.RootWorkItem.Services.AddNew(); 

并使用以下两种方式之一访问:

 WorkItem.Services.Get() [ServiceDependency] public IErgaenzungsfeldService ErgaenzungsfeldService { get; set; } 

问题:并不总是调用ErgaenzungsfeldService.NotifyEntityChanged。 这仅在导入数据时发生,而不是在“正常”使用应用程序时发生。 通常我的意思是可以在应用程序中修改ErgaenzungsfeldEntity并保存。 正在使用相同的机制并且有效。

一些观察:

  • 导入过程是单线程的。 它不在UI线程中运行。
  • 当ErgaenzungsfeldService.NotifyEntityChanged不是正确调用DienstleistenderService.NotifyEntityChanged时
  • 通过NotifyEntityChanged(pNotifyEventItem.ToArray())System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandlePersPlanChanged(NotifyPersPlanChanged)); NotifyEntityChanged(pNotifyEventItem.ToArray())替换Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandleEntityChanged(NotifyEntityChanged), pNotifyEventItem.ToArray()) System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new HandlePersPlanChanged(NotifyPersPlanChanged)); 正确调用ErgaenzungsfeldService.NotifyEntityChanged。 当UI从另一个线程获得通知时,应用程序显然会在以后抛出exception。
  • 如果通过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 m_dispatcherOperationresults = new List(); private void InternalFireNotification(List<NotifyEventItem> 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调度程序。