[英]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.