Jef*_*hao 9 c# wpf multithreading propertychanged inotifypropertychanged
我正在研究一个复杂的WPF应用程序,该应用程序几天就会挂起.除了GUI线程填充数据之外,还有一个线程可以将模型绑定到网格并触发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 ... )
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
It seems that someone is holding the WriteLock but never release - but how can I check who's holding that? I've paste the whole stacktrace I've got here, is someone to give me some hits on the root cause, like what's HwndSubclass and why it happens repeatedly in the stacktrace with the change of IsActive and WindowState property?
Please add comments if you need more information.
在深入研究几乎所有相关组件的源代码后,我终于解决了这个问题。感谢出色的参考源网站,源代码中的注释与 ILSpy 的反编译结果相比有很大帮助。
PropertyChangedEventManager?PropertyChangedEventManager(此处为源代码)是一个在并发环境ProperyChanged中处理事件处理程序和通知的组件。换句话说,它是线程安全的。在内部它使用 a来保持线程安全。当事件处理程序发生更改时,将获取写入锁;当有事件通知时,将获取读取锁。ReaderWriterLockPropertyChanged
PropertyChangedEventManager通常由 WPF 控件使用。当我们将视图模型附加/分离到控件时,我们正在添加/删除PropertyChanged事件处理程序。我一直想知道谁持有写入器锁,从而阻止了读取器锁(get_ReadLock),但实际上是 GUI 线程本身。
是的,这听起来很奇怪,但它就在里面PrivateAddListener(这里是源代码),如堆栈跟踪所示:
...
[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)
...
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我总是被告知我们应该PropertyChanged从后台线程触发 UI 绑定对象中的事件,但事实并非如此,因为 .NET 4PropertyChangedEventManager被设计为在并发环境中使用。仅当模型绑定到 GUI 控件时才会使用独占(编写器)锁,并且该PropertyChanged事件可以同时从多个后台线程触发。我们不需要手动将所有内容编组到 GUI 线程。
实际上,在后台线程中更新模型是一种非常重要的模式,有时这是唯一可接受的方法。请考虑当我们有多个 GUI/STA 线程来提高应用程序的响应能力时的情况。我们可以将同一个实例绑定到不同 GUI 线程中的控件。当模型更改时,我们根本无法将PropertyChanged通知编组到其中任何一个中。跨线程通知是不可避免的。
SubclassWndProc?HwndSubclass.SubclassWndProc(此处为源代码)是处理窗口消息的托管代码的入口点。它由本机代码调用,因此我们始终可以在堆栈跟踪中找到它之前的[IL Method without Metadata]和。[Internal Frame, 'M-->U']
SubclassWndProc奇怪的是,为什么堆栈跟踪中会有多个调用?难道窗口消息不应该一个接一个地单独处理吗?为了回答这个问题,我们需要检查堆栈跟踪中重复出现的方法的代码:
...
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)
...
Run Code Online (Sandbox Code Playgroud)
从源代码中我注意到这些方法正在处理WM_ACTIVATE消息(好吧,我们也可以从名称中看出)。这是MSDN 中描述的特殊消息:
发送到正在激活的窗口和正在停用的窗口。如果窗口使用相同的输入队列,则消息将同步发送,首先发送到正在停用的顶级窗口的窗口过程,然后发送到正在激活的顶级窗口的窗口过程。如果窗口使用不同的输入队列,则消息是异步发送的,因此窗口会立即激活。
由于该消息是在 GUI 线程中同步发送的,因此不会完成当前消息,而是会立即处理该消息。这就是我们可以在堆栈跟踪中找到递归调用的原因。
它还解释了为什么WindowViewMode.IsActive要多次设置:
WindowViewModel.set_IsActive(value=True)WindowViewModel.set_IsActive(value=False)WindowViewModel.set_IsActive(value=True)因为它会被“停用”并再次“激活”。
我们WindowViewModel有一个IsActive与属性同步的属性Window.IsActive。请注意,它不是双向绑定,因为该属性是只读的。当窗口被激活时,WindowViewModel.IsActive属性将被设置并触发PropertyChanged事件。由于WPF控件已经和视图模型挂钩了,所以执行内部逻辑。
我不清楚详细的逻辑是什么(它是[IL Method without Metadata]),但不幸的是它产生了一条新消息WM_ACTIVATE。这种情况一次又一次地发生,最终停止了 GUI 线程。
在确保我们没有使用WindowViewModel.IsActivein 绑定后,我将其更改为IsActive()方法。我们不需要触发该PropertyChanged事件,因为它不再是一个属性。
我还留言说,如果我们确实需要IsActive成为一个属性,我们需要确保事件PropertyChanged在内部触发Dispatcher.BeginInvoke,即使它已经在 GUI 线程中。我们需要确保下一条WM_ACTIVATE消息是异步生成的。
但我仍然无法解释为什么ReaderWriterLock当我们第三次或第四次获取读者锁时会阻塞。我确实认为我们有更深层次的递归PropertyChanged通知,因此读取器锁将比当前情况获得更多次。但每次遇到这个问题时,我们总是IsActive在堆栈跟踪中找到该属性。
ReaderWriterLockWPF 甚至操作系统中是否有任何特殊保护?
| 归档时间: |
|
| 查看次数: |
3630 次 |
| 最近记录: |