c# - WPF应用程序在并发环境中被PropertyChangedEventManager挂起

标签 c# wpf multithreading inotifypropertychanged propertychanged

我正在研究一个复杂的WPF应用程序,该应用程序在生产中挂起了几天。除了GUI线程之外,还有一个线程将数据填充到模型并绑定(bind)到网格并触发INotifyPropertyChanged.PropertyChanged事件。我编写了一个脚本,将MDbg附加到挂起的进程并转储线程的当前堆栈跟踪。在找到死锁的原因时,它很有用,但这次却无济于事。

正在更新模型的线程在获取ReadLock时停止:

Thread [#:8]
*0. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock()  (source line information unavailable)
 1. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=<...>, args=System.ComponentModel.PropertyChangedEventArgs)  (source line information unavailable)
 2. ( ... firing PropertyChanged event ... )

GUI线程发生了相同的事情:
Thread [#:0]
*0. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock()  (source line information unavailable)
 1. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs)  (source line information unavailable)
 2. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive")  (source line information unavailable)
 3. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=True)  (source line information unavailable)
 4. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs)  (source line information unavailable)
 5. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>)  (source line information unavailable)
 6. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>)  (source line information unavailable)
 7. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>)  (source line information unavailable)
 8. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>)  (source line information unavailable)
 9. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>)  (source line information unavailable)
 10. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>)  (source line information unavailable)
 11. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>)  (source line information unavailable)
 12. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>)  (source line information unavailable)
 13. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 14. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 15. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 16. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>)  (source line information unavailable)
 17. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 18. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>)  (source line information unavailable)
 19. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>)  (source line information unavailable)
 20. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 21. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>)  (source line information unavailable)
    [IL Method without Metadata]
 22. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock()  (source line information unavailable)
 23. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs)  (source line information unavailable)
 24. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive")  (source line information unavailable)
 25. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=False)  (source line information unavailable)
 26. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs)  (source line information unavailable)
 27. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>)  (source line information unavailable)
 28. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>)  (source line information unavailable)
 29. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>)  (source line information unavailable)
 30. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>)  (source line information unavailable)
 31. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>)  (source line information unavailable)
 32. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>)  (source line information unavailable)
 33. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>)  (source line information unavailable)
 34. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>)  (source line information unavailable)
 35. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 36. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 37. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 38. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>)  (source line information unavailable)
 39. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 40. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>)  (source line information unavailable)
 41. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>)  (source line information unavailable)
 42. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 43. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>)  (source line information unavailable)
    [IL Method without Metadata]
 44. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock()  (source line information unavailable)
 45. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs)  (source line information unavailable)
 46. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive")  (source line information unavailable)
 47. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=True)  (source line information unavailable)
 48. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs)  (source line information unavailable)
 49. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>)  (source line information unavailable)
 50. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>)  (source line information unavailable)
 51. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>)  (source line information unavailable)
 52. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>)  (source line information unavailable)
 53. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>)  (source line information unavailable)
 54. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>)  (source line information unavailable)
 55. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>)  (source line information unavailable)
 56. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>)  (source line information unavailable)
 57. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 58. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 59. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 60. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>)  (source line information unavailable)
 61. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 62. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>)  (source line information unavailable)
 63. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>)  (source line information unavailable)
 64. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 65. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>)  (source line information unavailable)
    [IL Method without Metadata]
 66. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.PrivateAddListener(source=<N/A>, listener=<N/A>, propertyName=<N/A>)  (source line information unavailable)
 67. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.ReplaceItem(k=<N/A>, newO=<N/A>, parent=<N/A>)  (source line information unavailable)
 68. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(k=<N/A>, collectionView=<N/A>, newValue=<N/A>, isASubPropertyChange=<N/A>)  (source line information unavailable)
 69. PresentationFramework.dll#0!MS.Internal.Data.ClrBindingWorker.AttachDataItem()  (source line information unavailable)
 70. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.Activate(item=<N/A>)  (source line information unavailable)
 71. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.AttachToContext(attempt=<N/A>)  (source line information unavailable)
 72. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(lastChance=<N/A>)  (source line information unavailable)
 73. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine+Task.Run(lastChance=<N/A>)  (source line information unavailable)
 74. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine.Run(arg=<N/A>)  (source line information unavailable)
 75. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine.OnLayoutUpdated(sender=<N/A>, e=<N/A>)  (source line information unavailable)
 76. PresentationCore.dll#0!System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()  (source line information unavailable)
 77. PresentationCore.dll#0!System.Windows.ContextLayoutManager.UpdateLayout()  (source line information unavailable)
 78. PresentationCore.dll#0!System.Windows.ContextLayoutManager.UpdateLayoutCallback(arg=<N/A>)  (source line information unavailable)
 79. PresentationCore.dll#0!System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()  (source line information unavailable)
 80. PresentationCore.dll#0!System.Windows.Media.MediaContext.RenderMessageHandlerCore(resizedCompositionTarget=<N/A>)  (source line information unavailable)
 81. PresentationCore.dll#0!System.Windows.Media.MediaContext.RenderMessageHandler(resizedCompositionTarget=<N/A>)  (source line information unavailable)
 82. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 83. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>)  (source line information unavailable)
 84. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>)  (source line information unavailable)
 85. WindowsBase.dll#0!System.Windows.Threading.DispatcherOperation.InvokeImpl()  (source line information unavailable)
 86. mscorlib.dll#0!System.Threading.ExecutionContext.runTryCode(userData=<N/A>)  (source line information unavailable)
 87. mscorlib.dll#0!System.Threading.ExecutionContext.Run(executionContext=<N/A>, callback=<N/A>, state=<N/A>, ignoreSyncCtx=<N/A>)  (source line information unavailable)
 88. mscorlib.dll#0!System.Threading.ExecutionContext.Run(executionContext=<N/A>, callback=<N/A>, state=<N/A>)  (source line information unavailable)
 89. WindowsBase.dll#0!System.Windows.Threading.DispatcherOperation.Invoke()  (source line information unavailable)
 90. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.ProcessQueue()  (source line information unavailable)
 91. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WndProcHook(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 92. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
 93. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>)  (source line information unavailable)
 94. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 95. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>)  (source line information unavailable)
 96. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>)  (source line information unavailable)
 97. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>)  (source line information unavailable)
 98. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>)  (source line information unavailable)
    [IL Method without Metadata]
    [Internal Frame, 'M-->U']
    [IL Method without Metadata]
 99. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.PushFrameImpl(frame=<N/A>)  (source line information unavailable)
 100. PresentationFramework.dll#0!System.Windows.Application.RunInternal(window=<N/A>)  (source line information unavailable)
 101. PresentationFramework.dll#0!System.Windows.Application.Run()  (source line information unavailable)
 102. MyProgram.exe#0!XamlGeneratedNamespace.GeneratedApplication.Main()  (source line information unavailable)

似乎有人拿着WriteLock却从不释放-但是我如何检查谁拿着它呢?我已经粘贴了我到这里的整个stacktrace,是否有人要给我一些根本原因的建议,例如HwndSubclass是什么,以及为什么随着IsActiveWindowState属性的更改,它在stacktrace中反复发生?

如果您需要更多信息,请添加评论。

最佳答案

在研究了几乎所有相关组件的源代码之后,我终于解决了该问题。多亏了梦幻般的Reference Source网站,与ILSpy的反编译结果相比,源代码中的注释有很大帮助。

什么是PropertyChangedEventManager
PropertyChangedEventManager(source code here)是在并发环境中处理ProperyChanged事件处理程序和通知的组件。换句话说,它是线程安全的。在内部,它使用ReaderWriterLock保持线程安全。更改事件处理程序时将获取编写器锁,而当存在PropertyChanged事件通知时将获取阅读器锁。
PropertyChangedEventManager通常由WPF控件使用。当我们将 View 模型附加/分离到控件时,我们将添加/删除PropertyChanged事件处理程序。我一直想知道是谁持有写作者锁,它阻止了读者锁(get_ReadLock),但实际上是GUI线程本身。

是的,这听起来很奇怪,但是它在PrivateAddListener(source code here)内部,如stacktrace所示:

...
[IL Method without Metadata]
 66. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.PrivateAddListener(source=<N/A>, listener=<N/A>, propertyName=<N/A>)  (source line information unavailable)
 67. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.ReplaceItem(k=<N/A>, newO=<N/A>, parent=<N/A>)  (source line information unavailable)
...

顺便说一句,我总是被告知我们应该从后台线程在UI绑定(bind)的对象中触发PropertyChanged事件,但是自从.NET 4以来,情况并非如此。PropertyChangedEventManager设计为可在并发环境中使用。排他(写入)锁仅在模型绑定(bind)到GUI控件时才使用,并且PropertyChanged事件可以同时从多个后台线程触发。我们不需要手动将所有内容编码(marshal)至GUI线程。

实际上,这是在后台线程中更新模型的非常重要的模式,有时这是唯一可接受的方法。请考虑以下情况:当我们有多个GUI/STA线程来提高应用程序的响应速度时。我们可以将同一实例绑定(bind)到不同GUI线程中的控件。更改模型后,我们根本无法将PropertyChanged通知编码到其中任何一个中。跨线程通知是不可避免的。

什么是SubclassWndProc
HwndSubclass.SubclassWndProc(source code here)是用于处理窗口消息的托管代码的入口点。它由 native 代码调用,因此我们始终可以在堆栈跟踪中找到[IL Method without Metadata][Internal Frame, 'M-->U']

奇怪的是,为什么在堆栈跟踪中会有几个SubclassWndProc调用?难道不应该分别一个接一个地处理窗口消息吗?要回答这个问题,我们需要检查方法的代码在stacktrace中重复出现:
...
 55. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>)  (source line information unavailable)
 56. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>)  (source line information unavailable)
 57. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>)  (source line information unavailable)
...

从源代码中,我注意到这些方法正在处理WM_ACTIVATE消息(好的,我们也可以从名称中分辨出来)。这是一条特殊消息as decribed in MSDN:

Sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the top-level window being deactivated, then to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately.



由于该消息是在GUI线程中同步发送的,因此无需完成当前消息即可立即对其进行处理。这就是我们可以在堆栈跟踪中找到递归调用的原因。

它还解释了为什么WindowViewMode.IsActive设置了多次:

#47中的
  • -WindowViewModel.set_IsActive(value=True)
  • #25中的
  • -WindowViewModel.set_IsActive(value=False)
  • #3中的
  • -WindowViewModel.set_IsActive(value=True)

  • 因为它将被“停用”并再次“激活”。

    根本原因和解决方案

    WindowViewModel中,我们有一个IsActive属性,该属性与Window.IsActive属性同步。请注意,由于该属性是只读的,所以它不是双向绑定(bind)。激活窗口后,将设置WindowViewModel.IsActive属性并触发PropertyChanged事件。由于WPF控件已与 View 模型关联,因此将执行内部逻辑。

    我不清楚具体的逻辑(它是[IL Method without Metadata]),但是不幸的是,它会产生一条新的WM_ACTIVATE消息。这一次又一次地发生,并最终停止了GUI线程。

    确保我们没有在绑定(bind)中使用WindowViewModel.IsActive后,将其更改为IsActive()方法。我们不再需要触发PropertyChanged事件,因为它不再是属性。

    我还发表了一条评论,说如果确实需要将IsActive作为属性,则需要确保PropertyChanged事件在Dispatcher.BeginInvoke内部触发,即使该事件已经在GUI线程中也是如此。我们需要确保下一个WM_ACTIVATE消息是异​​步生成的

    我无法解释的一件事

    但是我仍然无法解释为什么当我们第三次或第四次获取阅读器锁时ReaderWriterLock会阻塞。我确实认为我们具有更深的递归PropertyChanged通知,因此读取器锁的获取次数将比当前情况更多。但是,每次遇到此问题时,我们总是在堆栈跟踪中具有IsActive属性。
    ReaderWriterLock或WPF甚至在操作系统中是否有任何特殊保护?

    关于c# - WPF应用程序在并发环境中被PropertyChangedEventManager挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24054940/

    相关文章:

    c# - 用于查找最近的前一个兄弟的 XPath 语句

    c# - 没有无限循环的堆栈溢出异常(据我所知)

    c# - 简化代码 C# switch 语句

    java - 在android中每2小时调用一次方法的最佳方法?

    c# - SqlConnection/SqlCommand 线程安全吗?

    c# - 当 "break all"没有响应时,如何调试无响应的 .Net 服务?

    c# - HashSet 中的剩余值进入辅助输出

    wpf - 如何关闭 WPF Toolkit 图表中的动画

    java - 线程中的 NoClassDefFoundError

    c# - 使用泛型类型和表达式的扩展方法选择