使用 SynchronizationContext 将事件发送回 WinForms 或 WPF 的 UI

2024-01-08

我使用 SynchronizationContext 将事件从执行大量多线程后台任务的 DLL 封送回 UI 线程。

我知道单例模式不是我最喜欢的,但是当您创建 foo 的父对象时,我现在使用它来存储 UI 的 SynchronizationContext 的引用。

public class Foo
{
    public event EventHandler FooDoDoneEvent;

    public void DoFoo()
    {
        //stuff
        OnFooDoDone();
    }

    private void OnFooDoDone()
    {
        if (FooDoDoneEvent != null)
        {
            if (TheUISync.Instance.UISync != SynchronizationContext.Current)
            {
                TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(); }, null);
            }
            else
            {
                FooDoDoneEvent(this, new EventArgs());
            }
        }

    }
}

这在 WPF 中根本不起作用,TheUISync 实例 UI 同步(从主窗口提供)永远不会与当前的 SynchronizationContext.Current 匹配。在 Windows 窗体中,当我做同样的事情时,它们将在调用后匹配,我们将返回到正确的线程。

我讨厌的修复看起来像

public class Foo
{
    public event EventHandler FooDoDoneEvent;

    public void DoFoo()
    {
        //stuff
        OnFooDoDone(false);
    }

    private void OnFooDoDone(bool invoked)
    {
        if (FooDoDoneEvent != null)
        {
            if ((TheUISync.Instance.UISync != SynchronizationContext.Current) && (!invoked))
            {
                TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(true); }, null);
            }
            else
            {
                FooDoDoneEvent(this, new EventArgs());
            }
        }

    }
}

所以我希望这个样本有足够的意义来遵循。


眼前的问题

你眼前的问题是SynchronizationContext.Current不会自动为 WPF 设置。要设置它,当在 WPF 下运行时,您需要在 TheUISync 代码中执行类似的操作:

var context = new DispatcherSynchronizationContext(
                    Application.Current.Dispatcher);
SynchronizationContext.SetSynchronizationContext(context);
UISync = context;

更深层次的问题

SynchronizationContext与 COM+ 支持结合在一起,并且被设计为跨线程。在 WPF 中,您不能拥有跨多个线程的调度程序,因此SynchronizationContext不能真正跨线程。在许多情况下,SynchronizationContext可以切换到一个新线程 - 特别是任何调用ExecutionContext.Run()。所以如果你正在使用SynchronizationContext要向 WinForms 和 WPF 客户端提供事件,您需要注意某些情况会中断,例如对托管在同一进程中的 Web 服务或站点的 Web 请求将会出现问题。

如何避免需要 SynchronizationContext

因此我建议使用 WPFDispatcher专门用于此目的的机制,即使使用 WinForms 代码也是如此。您已经创建了一个“TheUISync”单例类来存储同步,因此显然您有某种方法可以连接到应用程序的顶层。无论您这样做,您都可以添加代码,将一些 WPF 内容添加到您的 WinForms 应用程序中,以便Dispatcher会起作用,然后使用新的Dispatcher我在下面描述的机制。

使用 Dispatcher 代替 SynchronizationContext

WPF's Dispatcher机制实际上消除了对单独的SynchronizationContext目的。除非您有某些互操作场景,例如与 COM+ 对象或 WinForms UI 共享代码,否则最好的解决方案是使用Dispatcher代替SynchronizationContext.

这看起来像:

public class Foo 
{ 
  public event EventHandler FooDoDoneEvent; 

  public void DoFoo() 
  { 
    //stuff 
    OnFooDoDone(); 
  } 

  private void OnFooDoDone() 
  { 
    if(FooDoDoneEvent!=null)
      Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Normal, new Action(() =>
        {
          FooDoDoneEvent(this, new EventArgs()); 
        }));
  }
}

请注意,您不再需要 TheUISync 对象 - WPF 会为您处理该详细信息。

如果你更喜欢与年长的人相处delegate语法你可以这样做:

      Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Normal, new Action(delegate
        {
          FooDoDoneEvent(this, new EventArgs()); 
        }));

需要修复的不相关错误

另请注意,您的原始代码中存在一个错误,该错误已在此处复制。问题在于,在调用 OnFooDoDone 的时间和调用 OnFooDoDone 的时间之间,FooDoneEvent 可以设置为 null。BeginInvoke (or Post在原始代码中)调用委托。修复方法是委托内部的第二个测试:

    if(FooDoDoneEvent!=null)
      Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Normal, new Action(() =>
        {
          if(FooDoDoneEvent!=null)
            FooDoDoneEvent(this, new EventArgs()); 
        }));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 SynchronizationContext 将事件发送回 WinForms 或 WPF 的 UI 的相关文章

  • C# 中 value 为匿名类型的字典

    是否可以在 C 中创建一个System Collections Generic Dictionary
  • 利用 SLURM 上的所有 CPU

    我想在集群上运行作业 不同节点上有不同数量的 CPU 我不知道哪些节点将分配给我 正确的选项是什么 以便作业可以在所有节点上创建与 CPU 一样多的任务 bin bash l SBATCH p normal SBATCH N 4 SBATC
  • 我的代码线程不安全吗?

    我编写了代码来理解 CyclicBarrier 我的应用程序模拟选举 每轮选出得票少的候选人 该候选人从竞争中淘汰以获得胜利 source class ElectoralCommission public volatile boolean
  • 底部垂直滚动richtextbox [WPF]

    我有一个富文本框 当满了时我想自动滚动到底部 这可能吗 用xaml做这个吗 通过使用ScrollViewer ScrollChanged http msdn microsoft com en us library system window
  • Python 线程与 Linux 中的多处理

    基于此question https stackoverflow com questions 807506 threads vs processes in linux我假设创建新流程应该几乎和创造新线程在Linux中 然而 很少的测试显示出截
  • 需要多少个线程才能使它们成为错误的选择?

    我必须使用 boost thread 用 C 编写一个不太大的程序 当前的问题是处理大量 可能是数千或数万 数百和数百万也是可能的 数量 可能 的大文件 每个文件彼此独立 并且它们都驻留在同一目录中 我正在考虑使用多线程方法 但问题是 我应
  • ORM 之于 RDBMS 就像 xxx 之于 OLAP 多维数据集一样? xxx存在吗?

    是否有用于查询 OLAP 多维数据集 数据仓库的 ORM 类似物 我对 NET 世界特别感兴趣 但一般对任何事物都感兴趣 我启动了一个开源项目 Kona 来包装 ADOMD Net 库 并尝试将 ADOMD Net 引入 21 世纪 你可以
  • 如何在运行时动态更改 DataGrid String 列格式?

    我的 WPF 桌面应用程序提供了一个 UI 来搜索人员并在 DataGrid 中显示结果 此外 用户可以在运行时更改语言 Current UI Culture XAML 中的 DataGrid 定义是
  • PostSharp 如何在运行时知道某个方面是否应用于方法?

    我正在实现 PostSharp 方面库 但无法找到以下问题的解决方案 假设我们有一个方面将应用于某些方法 而不会应用于其他方法 我需要某种可以在运行时使用的机制来了解某个方面是否应用于方法 具体来说 在运行时确定某些方面是否应用于由 a 给
  • 在代码后面绑定属性

    我有 WPF 应用程序和其中的一个窗口 让我们在我的 xml 中添加这样的内容
  • clang 3.0 + libc++ 中的 std::async 不起作用?

    我刚刚在我的 ubuntu 10 04 上编译并安装了 clang llvm 3 0 并且还从 svn 编译并安装了 libc 由于 libc 中的状态显示线程支持已完成 因此我想尝试 std async 所以我按照安东尼 威廉姆斯 Ant
  • 将 .NET 小数存储到 MySQL 中的最佳字段定义是什么?

    我需要将小数存储到 MySQL 中 它可以具有不同的精度 因此我很想知道哪种 MySQL 字段类型绝对等同于 NET 的字段类型decimal http msdn microsoft com en us library system dec
  • 链接 C++ 和 C++/CLI 项目 (.NET Core) 时导入错误 (E0337)

    我目前正在尝试建立一个 NET 项目 我有一个现有的 C 后台项目 我想将其显示在 Web 界面上 为此 我尝试通过以下方式将我的 C 链接到 NET 平台 CLR 类库 NET Core 并最终将其链接到ASP NET 网络界面但这是下一
  • 如何找到可能直接或间接调用给定方法的所有单元测试? (。网)

    如何找到可能直接或间接调用给定方法的所有单元测试 当我改变方法时 我希望知道要运行的最佳测试 必须有一个工具可以做到这一点 由于我们有很多接口 所以我对所有在实现接口的类上至少有一个路径 var 植入方法时调用接口上的方法的单元测试感兴趣
  • WPF 中的图像变得模糊

    我正在使用 C 在 WPF 中开发应用程序 我将图像放入 WrapPanel 中 并在带有一个边框的网格内显示 并在按钮中使用图像 问题是我的图像控件失去了质量 我无法在这里发布我的图片 所以我只是在这里描述 I used SnapsToD
  • ReST 代理对象生成器

    第三方公司写了一套ReST服务 我已经让所有代码正常工作 但事后看来 为了消除一些跑腿工作 我认为有人可能知道一个代码生成器 它连接到 ReST 服务并计算出需要创建和生成哪些请求和响应对象这些的代码 我在谷歌上看了一下 但没有看到任何合适
  • 从 .Net 将简单数据插入 Excel 文件的最简单方法

    我有一个 Excel 文件 大约有 10 列和 1 20 行 我需要插入 1 20 行包含各种数据元素 我想知道是否有一种方法可以将一些标签放入 Excel 文件中 以便可以找到并替换它们 将列标记为 名称 的东西 这样我就可以在代码中说
  • 隐形打开的弹出窗口

    第二天就解决这个问题 要重现 请创建新的 WPF 应用程序 xaml
  • .NET 的 HttpWebResponse 是否会自动解压缩 GZiped 和 Deflated 响应?

    我正在尝试执行一个接受压缩响应的请求 var request HttpWebRequest HttpWebRequest Create requestUri request Headers Add HttpRequestHeader Acc
  • 领域驱动设计示例(特别是 .NET 重点)

    好的 我已经订购了 但是当我等待它到达时 我正在考虑开始在我当前的项目中应用这些技术 我现在确实很好地掌握了这些概念 但是当我尝试应用它们时 我陷入了执行过程中 最终在各个项目中漏掉了我的职责 因此 我正在寻找可以引导我走向正确方向的资源

随机推荐

  • 从 Leaps regsubsets 获取所有模型

    我使用 regsubsets 来搜索模型 是否可以自动创建所有lm从参数选择列表中 library leaps leaps lt regsubsets y x1 x2 x3 data nbest 1 method exhaustive su
  • 如何将 json 编码的 PHP 数组转换为 Javascript 中的数组? [复制]

    这个问题在这里已经有答案了 我正在使用 AJAX 从 PHP 文件中获取 JSON 编码的数组 但在 JavaScript 中我需要将其用作数组 如何在 Javascript 中创建数组 我对 PHP 文件的 AJAX 调用 ajax ty
  • 如何在 Spinner 中选择项目并将其用作字符串?

    只是想看看我是否可以找出如何在微调器中选择项目并将其存储在字符串中 我已经看到了有关此问题的其他帖子 人们说将此行放入代码中 在我在下面发布的代码的最后一行下面 String Genders Gender getSelectedItem t
  • 将代码分配给动态创建的按钮

    我正在尝试获取一个在 Excel 用户表单上动态创建的按钮来运行名为的宏transfer我写过的Module 1我的项目的 模块 部分 下面我将迄今为止编写的代码粘贴到用户窗体中 该窗体实际上设法创建了Transfer to Sheet框架
  • “创建用户”怎么写?使用 MySQL 准备好的语句

    I tried SET user foo localhost SET pass bar SET sql CREATE USER IDENTIFIED BY PREPARE stmt FROM sql 我得到错误 ERROR 1064 420
  • FastAI lrfind()方法无法正常工作

    Update 1 我根据 无论坡度如何 你都希望从该点返回 10 倍 更新了我的 lr 并将其设置为 max lr 切片 1e 3 1e 2 这就是我得到的 和情节 这是什么意思 正如您在第二张图中看到的那样 从 1e 08 开始损失就非常
  • 为什么 JUnit 中不推荐使用assertEquals(double,double)?

    我想知道为什么assertEquals double double 已弃用 I used import static org junit Assert assertEquals 我使用的是 JUnit 4 11 下面是我的代码 import
  • 返回指向本地结构的指针

    我看到一些具有如下结构的代码示例 type point struct x y int func newPoint point return point 10 20 我有 C 背景 这对我来说似乎是错误 这种构造的语义是什么 新的点是分配在栈
  • 在行内插入表格

    我编写了一个包含两个表的脚本 tbl1是一个主表 tbl2是我想插入到的第二个表tbl1第二行使用纯JavaScript 它工作完美 但是我的tbl2有一些html attribute 插入后看到代码时没有看到 note tbl1 and
  • 如何用 PHP 解析 phpDoc 风格的注释块?

    请考虑以下代码 我尝试仅解析文件中的第一个 phpDoc 样式注释 不使用任何其他库 出于测试目的 将文件内容放入 data 变量中 data file A lot of info about this file Could even co
  • 为包含集合的对象实现 GetHashCode()

    考虑以下对象 class Route public int Origin get set public int Destination get set 路由实现相等运算符 class Routing public List
  • 术语“Update-Database”未被识别为 cmdlet 的名称

    我正在使用 EF5 beta1 虽然我之前能够运行 更新数据库 现在我关闭了 Visual Studio 我无法让它运行 我收到以下错误 术语 更新数据库 不被识别为 cmdlet 函数 脚本文件或可操作程序的名称 检查名称的拼写 或者如果
  • 解释 sed、grep 和 cut 语法

    我正在分析一个批处理文件 其中有一行编辑文本文件 输入 并制作 txt 文件 输出 该批处理使用三个帮助tools exe grep sed and cut 我尝试阅读他们的使用手册 但这并不容易 该行是 type input txt se
  • 带有“-std=c++0x”的“#include ”已损坏

    如果我指定 std c 0x到 g 那么我不能 include
  • CSS 性能和实现较少

    将 LESS 用于 CSS 的最佳方法是什么 基本上 开发人员应该编写一个 Less 文件 然后将其编译用于生产 我应该链接 LESS 代码和 javascript 文件吗 或者我应该完全跳过 LESS 路线并重新制作课程 我正在尝试将一些
  • 如何使用 HTML 父子关系中的 2 个 Svelte 组件将数据从子级传递到父级

    我是 Svelte 的新手 我在 HTML 父子关系中有 2 个 Svelte 组件 而不是 Svelte P C 关系 其中 1 个 Svelte 组件导入另一个组件 最终 我想要这样的东西 可能有很多 Accs
  • 如何在elasticsearch中使用Query DSL找到最近/最近的数字

    我正在寻找在弹性搜索的帮助下找到最近的价格 号码的可能性 问题是我没有范围 我想要实现的是结果按最近距离排序 根据示例搜索查询 我的索引包含 3 个文档 其价格 数字 如下 45 27 32 对于给定数字 距我的搜索值 29 的 距离 是
  • 谷歌搜索网络抓取与Python中的关键字列表

    我正在尝试通过使用名称列表作为输入并在 DataFame 中获取数据集来在 Google 搜索上进行网络抓取 我之前使用 selenium 进行网页抓取 但我在构建语法时遇到了困难使用循环运行名称列表作为输入得到结果并scrape每一页 下
  • 防止创建类型别名实例

    是否可以阻止创建类型别名的实例 例如一个ValidatedEmail type ValidatedEmail address string validatedOn Date 假设有一个函数validateEmail和一个函数sendEmai
  • 使用 SynchronizationContext 将事件发送回 WinForms 或 WPF 的 UI

    我使用 SynchronizationContext 将事件从执行大量多线程后台任务的 DLL 封送回 UI 线程 我知道单例模式不是我最喜欢的 但是当您创建 foo 的父对象时 我现在使用它来存储 UI 的 Synchronization