我正在处理一个复杂的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 ... )
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
但却从不释放 - 但我怎么能检查谁持有那个?我已经粘贴了我在这里的整个堆栈跟踪,有人给我一些关于根本原因的点击,比如什么HwndSubclass
以及为什么它在堆栈跟踪中反复出现更改IsActive
和WindowState
属性?
如果您需要更多信息,请添加评论。
答案 0 :(得分:4)
在深入研究几乎所有相关组件的源代码之后,我终于解决了这个问题。感谢精彩的Reference Source网站,源代码中的注释与ILSpy的反编译结果相比有很大的帮助。
PropertyChangedEventManager
? PropertyChangedEventManager
(source code here)是在并发环境中处理ProperyChanged
事件处理程序和通知的组件。换句话说,它是线程安全的。在内部,它使用ReaderWriterLock
来保持线程安全。更改事件处理程序时将获取编写器锁定,并在发生PropertyChanged
事件通知时获取读取器锁定。
PropertyChangedEventManager
通常由WPF控件使用。当我们将视图模型附加/分离到控件时,我们会添加/删除PropertyChanged
事件处理程序。我总是想知道谁拿着写入锁来阻止读者锁(get_ReadLock
),但实际上它是GUI线程本身。
是的,听起来很奇怪,但它只是在PrivateAddListener
(source code here)内,因为堆栈跟踪显示:
...
[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绑定对象中触发PropertyChanged
事件,但是自.NET 4以来情况并非如此。PropertyChangedEventManager
被设计在并发环境中使用。仅当模型绑定到GUI控件时才使用独占(编写器)锁,并且可以同时从多个后台线程触发PropertyChanged
事件。我们不需要手动将所有内容编组到GUI线程中。
实际上,它是在后台线程中更新模型的一个非常重要的模式,有时这是唯一可接受的方法。请考虑我们有多个GUI / STA线程来提高应用程序响应能力的情况。我们可以将同一个实例绑定到不同GUI线程中的控件。当模型发生变化时,我们根本无法将PropertyChanged
通知编组到其中任何一个中。交叉线程通知是不可避免的。
SubclassWndProc
? HwndSubclass.SubclassWndProc
(source code here)是处理窗口消息的托管代码的入口点。它由本机代码调用,因此我们始终可以在堆栈跟踪中找到[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)
...
从源代码中我注意到这些方法正在处理WM_ACTIVATE
消息(好的我们也可以从名称中告诉它)。这是一条特殊消息as decribed in MSDN:
发送到正在激活的窗口和停用的窗口。 如果窗口使用相同的输入队列,则会同步发送消息,首先是要停用的顶级窗口的窗口过程,然后是要激活的顶级窗口的窗口过程。如果窗口使用不同的输入队列,则会异步发送消息,因此窗口会立即激活。
由于消息是在GUI线程中同步发送的,因此将立即处理,而不会完成当前消息。这就是我们可以在堆栈跟踪中找到递归调用的原因。
它还解释了为什么多次设置WindowViewMode.IsActive
:
WindowViewModel.set_IsActive(value=True)
WindowViewModel.set_IsActive(value=False)
WindowViewModel.set_IsActive(value=True)
因为它会被停用&#34;和&#34;激活&#34;试。
在WindowViewModel
中,我们有IsActive
属性,该属性与Window.IsActive
属性同步。请注意,由于该属性是只读的,因此它不是双向绑定。激活窗口后,将设置WindowViewModel.IsActive
属性并触发PropertyChanged
事件。由于WPF控件已与视图模型连接,因此执行内部逻辑。
我不清楚逻辑的详细内容(它是[IL Method without Metadata]
)但不幸的是它产生了一条新的WM_ACTIVATE
消息。这种情况一次又一次地发生,最后停止了GUI线程。
确保我们未在绑定中使用WindowViewModel.IsActive
后,我将其更改为IsActive()
方法。我们不需要触发PropertyChanged
事件,因为它不再是属性。
我还发表评论说,如果我们确实要求IsActive
成为某个媒体资源,我们需要确保在PropertyChanged
内触发Dispatcher.BeginInvoke
事件,即使是WM_ACTIVATE
已经在GUI线程中。我们需要确保下一个ReaderWriterLock
消息是异步生成。
但我还是无法解释为什么PropertyChanged
会阻止我们第三次或第四次获取读卡器锁。我确实认为我们有更深层次的递归IsActive
通知,因此读取器锁定的获取次数比当前情况要多。但每次遇到这个问题时,我们总是在堆栈跟踪中有ReaderWriterLock
属性。
在{{1}}或WPF中,甚至在操作系统中是否有任何特殊保护?
答案 1 :(得分:2)
不要这样做。没有安全的方法从后台线程更新UI绑定对象。充其量它可能会工作一段时间,然后再次打破可怕的原因。除了GUI线程填充数据之外的一个线程,模型绑定到网格并触发INotifyPropertyChanged.PropertyChanged事件。
如果您正在进行I / O绑定呼叫,请不要使用后台线程。而是使用async / await语法来避免阻塞和处理UI线程上的所有内容。
如果您受CPU限制,那么您需要将更新编组回UI线程。我会分批而不是按对象进行此操作,因为线程编组可能很昂贵。
答案 2 :(得分:0)
看起来很可疑在同一个callstack中你正在改变IsActive属性的值3次:
由于#54,#32和#10中的依赖属性更改分别调用了所有三次setter。 你能检查一下你的来源并解释两件事:
这就是为什么我假设您已经为IsActive属性使用TwoWay绑定的原因,并建议在我的评论中用OneWay / OneWayToSource绑定替换它,因为这样的更改将消除UI和ViewModel层之间可能的干扰