c# - WPF和WinForms Dispatcher应该统一吗?

标签 c# .net wpf multithreading winforms

我有一个混合了 WPFWinForm 控件的应用程序,因为该项目早在 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)
….

这种行为是否记录在案? 由于我有 WinFormWPF 代码,所以有基于 WinForm 的代码使用 WinForm 机制触发 UI 线程(ISynchronizeInvoke of System. Windows.Forms.Control)。

这基本上混合了 WPFWinForms 分派(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/

相关文章:

c# - 将 ResourceDictionary 复制到 C# 中的字典

c# - 托管源代码管理?

c# - ClosedXML 以编程方式迭代工作表。

c# - 删除唯一约束并使用户名在 ASP.NET Identity 中可为空

C# 数据类型与 MySql 数据类型

c# - 如何在 C# windows 应用程序中将数据 gridview 条目中的记录插入到 SQL 数据库?

c# - 子属性中的 DataContract 父引用 - 如何避免无限序列化循环

wpf - 将 XAML 中的属性设置为函数

c# - 更新 ListBox 内的项目

c# - Rally SOAP API - 导入 .net 项目后缺少 RallyServiceService 类