我有一个混合了 WPF 和 WinForm 控件的应用程序,因为该项目早在 WPF 可用之前就开始了。 由于控件的数量以及需要向后兼容在其上构建更多应用程序的其他控件,因此不可能将所有控件更改为基于 WPF。
现在我偶尔会遇到导致“集合已修改” 异常的重入问题,因为当我们调用 WPF 调度程序消息时,它将导致其他未决的 WinForms 消息当我们发送 WPF 消息时,WinForms 端的意外消息泵送。
典型的调用堆栈以 WPF 调用开始,但最终调用改变 UI 状态的 BeginInvoke WinForm 消息。我可以通过事件处理程序更改 WPF 集合,该集合此时正在枚举。
….
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.DispatcherOperation.Wait(TimeSpan timeout)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherOperation operation, CancellationToken cancellationToken, TimeSpan timeout)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
虽然实际的 WPF 代码看起来是无辜的:
UIDispatcher.Current (this is WPF Dispatcher) .Invoke(new Action<string, …>(delegate(string msg, …)
{
this.statusModel.AddToStatus(msg, …);
}), new object[]
{
message,
icon
});
at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
….
这种行为是否记录在案? 由于我有 WinForm 和 WPF 代码,所以有基于 WinForm 的代码使用 WinForm 机制触发 UI 线程(ISynchronizeInvoke of System. Windows.Forms.Control)。
这基本上混合了 WPF 和 WinForms 分派(dispatch)的消息。摆脱这种困惑的推荐解决方案是什么?我是否应该将所有 WinForms Invoke/BeginInvoke 调用更改为对 WPF Dispatcher 调用的调用,以便我们有一个公共(public)消息处理队列而不是两个。或者有更好的方法吗?
更新 1
混合使用 WPF 和 WinForms 的问题也可以在这里找到更详细的信息:
最佳答案
如何嵌套您的调用,以便所有调用都从您选择的消息泵确定性地触发?
像这样:
yourWinFormsControl.Invoke((Action)(() =>
{
UIDispatcher.Current.Invoke(
(Action)(() =>
{
this.statusModel.AddToStatus(xyz);
}));
}));
这将创建一个 Action
,它调用 WPF 调度程序,但将其推送到 WinForms 调度程序。
关于c# - WPF和WinForms Dispatcher应该统一吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35156961/