C# / WPF 从另一个类中创建的另一个线程更新 UI

2023-12-08

我有嵌入式 C 背景,正在开发我的第一个 C# 应用程序,但我在这方面遇到了障碍,而且我的研究没有成功,所以我想我应该在这里问。

到目前为止,简单的应用程序。我有一个 MainWindow,除了一堆其他东西之外,还可以在单​​击按钮时启动 TCPClient 线程:

public partial class MainWindow : Window
{
 ....
       TCPConnection myCon = new TCPConnection();
 ....
   private void connectButton_Click(object sender, RoutedEventArgs e)
    {
        networkListBox.Items.Add("Connecting...");
        myCon.Connect("localhost", updateNetworkListBox);
    }
 }

 ....
    public void updateNetworkListBox(string message)
    {
        networkListBox.Items.Add(message);
    }

在 TCPConnection.cs 中:

   public class TCPConnection
   {
   ....
    public void Connect(string server, ReportDelegate reportDelegate)
    {
        this.server = server;
        clientThread = new Thread(() => Client(this.server));
        clientThread.Start();
        reportDelegate("Started client thread...");
    }

    static void Client(string server)
    {
        try
        {
            Int32 port = 25565;
            TcpClient client = new TcpClient(server, port);
            Byte[] outgoingBytes = new Byte[1024];
            string outgoingString = "Hello! I am " + Guid.NewGuid();
            outgoingBytes = System.Text.Encoding.ASCII.GetBytes(outgoingString);
            NetworkStream stream = client.GetStream();
            stream.Write(outgoingBytes, 0, outgoingBytes.Length);
            stream.Close();
            client.Close();
        }

既然 TCP 连接可以工作,我想做的第一件事就是向 UI 发送一条消息,例如“客户端线程连接...”、“客户端线程连接...”,并将其显示在网络列表框中。

在 Connect() 方法中,我可以通过使用委托来完成此操作,但这显然在新线程中不起作用,因为无法从另一个线程直接访问 UI 控件。

我已经阅读了大量有关此的文章,并且我知道我可能想使用调度程序来执行此操作。然而,我见过的几乎所有示例都在当前类中创建了一个新线程,例如,将匿名方法传递给 Dispatcher.Invoke()。

有一个例外this提倡使用 EventHandler 并在主窗口中初始化它的讨论。这似乎不太理想,但也许我错了。

再往下,还有人提倡数据共享。同样,这对我来说似乎不太理想。

我读过的其他文章似乎已经过时了。

因此,我欢迎任何有关如何解决此问题的解释。可能我只是在语法上感到困惑,但我怀疑,尽管我认为我对委托、lambda 等大部分内容都很清楚,但我可能对到底需要完成什么感到困惑。

如果您能通过一些解释来展示如何在这个特定示例中完成它,我将不胜感激。

也许还有一些对我来说有点模糊的具体问题:

1) 我的工作任务可以单独访问它还是必须由 UI 的调度程序提供?

2) UI 是否应该提供执行调度的委托,或者是否应该在工作任务中对调度进行编码,引用 UI Dispatcher?

非常感谢。


对于你关于提供样本的问题,如果有一个像这样的工人阶级......

public class Worker
{
    public Worker(Action<string>action)
    {
        Task.Run(() =>
        {
            int i = 0;
            while (true)
            {
                ++i;
                Task.Run(() => { action("Current value " + i); });
                Task.Run(() =>
                {
                    // doing some work here
                });
                Thread.Sleep(1000);
            }
        });
    }
}

...它在不同的线程上执行后台工作并通过委托向调用者提供建议。代表是一个普通的香草Action这需要一个字符串。然后,应该实现视图模型,使其不关心消息源自哪个线程。这是VM中的相应代码...

    private readonly SynchronizationContext _context = SynchronizationContext.Current;
    private void StartWorker()
    {
        Worker w = new Worker((s) => _context.Post(delegate { StatusText = s; }, null));
    }

此代码使用 SynchronizationContext,但也可以轻松使用调度程序。关键是 UI 线程上同步的责任不属于工作人员。工作人员不应该关心,同样,虚拟机是与线程无关的并且发布一切通过其 SynchronizationContext。

StatusText 属性的代码如下所示......

    private string _statusText;
    public string StatusText
    {
        [DebuggerStepThrough]
        get { return _statusText; }
        [DebuggerStepThrough]
        set
        {
            if (value != _statusText)
            {
                _statusText = value;
                OnPropertyChanged("StatusText");
            }
        }
    }

最后,在 UI 上,它是这样呈现的......

        <StatusBar DockPanel.Dock="Bottom">
            <TextBlock Text="{Binding StatusText}"/>
        </StatusBar>

...

因此,回顾一下您的问题:工作线程可以访问它,但它们应该not必须处理 UI 同步问题。该责任由 VM 承担。 VM 应该与线程无关,并通过调度程序或同步上下文或其他方法同步 UI。

如果您正在操作作为绑定主题的集合(例如 ObservableCollection),则通过 Dispatcher 进行调度是合适的;否则 SynchronizationContext 是合适的(它更轻量级)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# / WPF 从另一个类中创建的另一个线程更新 UI 的相关文章

  • C#9 顶级语句文件上的属性

    我正在尝试向顶级语句文件添加属性 但没有找到任何相关信息 是否可以 对于某些上下文 我想仅在该文件中禁用规则 SuppressMessage StyleCop CSharp LayoutRules SA1516 ElementsMustBe
  • C++ 有像 Pascal 一样的“with”关键字吗?

    withPascal 中的关键字可用于快速访问记录的字段 有人知道 C 是否有类似的东西吗 前任 我有一个包含许多字段的指针 但我不想这样输入 if pointer gt field1 pointer gt field2 pointer g
  • .NET Windows 服务中调用 C# 的 wait 的 I/O 回调是否可以不阻塞?

    我知道在 ASP NET 中 当使用 wait 时工作线程会返回到池中 而 I O 发生在后台 这对于可扩展性非常有用 我的 Windows 服务是一个套接字服务器 它使用 Begin End 样式的异步套接字 I O 混合我的魔法 我知道
  • C++ - 模板专业化和部分专业化

    我一直在互联网和 stackoverflow 上寻找具体的答案 但我似乎找不到 我必须创建一个通用类 然后实现特定的功能 我的具体说明是 您需要使用模板表达式参数以及模板类专业化和部分专业化 我有一个模板类 template
  • 此插件导致 Outlook 启动缓慢

    我正在使用 C NET 4 5 开发 Outlook Addin 项目 但部署后 有时 Outlook 会禁用我的插件 并显示此消息 这个插件导致 Outlook 启动缓慢 我不知道我的插件出了什么问题 这只有很少的代码 并且ThisAdd
  • 隐形打开的弹出窗口

    第二天就解决这个问题 要重现 请创建新的 WPF 应用程序 xaml
  • 将语句插入 SQL Server 数据库

    最近几天我试图找到这个错误 但没有成功 我正在尝试在数据库中插入一个新行 一切都很顺利 没有错误 也没有程序崩溃 My INSERT声明如下 INSERT INTO Polozaj Znesek Uporabnik Cas Kupec Po
  • 当我尝试使用 AVX 功能时,Clang 生成错误

    我使用的是 Windows 10 使用 Clang 版本 5 最近安装 当我编译以下内容时 define AVX define AVX2 include
  • Type_traits *_v 变量模板实用程序顺序无法编译

    看过了这个答案 https stackoverflow com a 31763111 7151494 我试图想出一个变量模板从中获取代码的实用程序 template
  • 使用 Microsoft Graph 创建用户

    如何使用 Microsoft graph 创建用户 因为我在保存过程中遇到了权限失败的问题 我确实有几个问题 在图中调用创建用户 API 将在哪里创建用户 是在 Azure AD 还是其他地方 我尝试通过传递 json 和必需的标头来调用创
  • C++ 析构函数:何时释放内存?

    如果我删除一个导致其析构函数被调用的对象 那么内存是在析构函数完成函数中的任何操作之前还是之后被释放 仅当最小派生类子对象被销毁后才会释放内存 所以如果你有 class Base class Derived public Base publ
  • 在 C# 中生成随机值

    如何使用以下命令生成随机 Int64 和 UInt64 值RandomC 中的类 这应该可以解决问题 这是一个扩展方法 因此您可以像调用普通方法一样调用它Next or NextDouble上的方法Random目的 public stati
  • 语义问题 Qt Creator:命名空间“std”中没有名为“cout”的成员

    我开始使用 Qt Creator 编写代码 对于 C 文件 我遇到很多语义问题 99 是 命名空间 yyy 中没有名为 xxx 的成员cpp文件构建 编译和输出没有问题 如果我点击例如cout 我已链接到 iostream 我是否需要在 Q
  • Unity 2.0 和处理 IDisposable 类型(特别是使用 PerThreadLifetimeManager)

    我知道类似的问题被问过好几次 例如 here https stackoverflow com questions 987761 how do you reconcile idisposable and ioc here https stac
  • 停止 TcpListener 的正确方法

    我目前正在使用 TcpListener 来处理传入连接 每个连接都有一个线程用于处理通信 然后关闭该单个连接 代码如下 TcpListener listener new TcpListener IPAddress Any Port Syst
  • 检索 Autofac 容器以解析服务

    在 C WindowForms 应用程序中 我启动一个 OWIN WebApp 它创建另一个类 Erp 的单例实例 public partial class Engine Form const string url http 8080 49
  • 统一;随机物体移动[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在制作一款机器人战斗游戏 我希望敌人随机移动 然后有时会向敌人移动 我希望运动包含在其中的代码 else if avoid fal
  • 获取大于某个数字的元素个数

    我正在尝试解决以下问题 数字被插入到容器中 每次插入数字时 我需要知道容器中有多少元素大于或等于当前插入的数字 我相信这两个操作都可以以对数复杂度完成 我的问题 C 库中有标准容器可以解决这个问题吗 我知道std multiset可以在对数
  • Crypto++ 和压缩 EC 密钥

    如何在 Crypto 中生成压缩的 ECDSA 密钥 AutoSeededRandomPool prng ECDSA
  • XmlDocument Save 使文件保持打开状态

    我有一个简单的 C 函数 可以创建一个基本的 XML 文件并保存 private void CreateXMlFile string Filename string Name string Company XmlDocument doc n

随机推荐

  • 在Python中展平嵌套列表[重复]

    这个问题在这里已经有答案了 我在扁平化 Python 中嵌套列表的部分时遇到一些困难 这是列表 31 1 32 8 16 1 3 12 4 12 32 1 3 12 4 12 32 30 1 1 我想展平该列表内的任何列表 最终结果如下所示
  • 在旋转矩阵之间插值

    我有 2 个旋转矩阵 我们称它们为 A 和 B 其中 A 1 0 0 0 0 1 0 1 0 and B 1 0 0 0 0 1 0 1 0 这基本上只是相机旋转以查看其后方的旋转 显然我不能直接对矩阵中的值进行插值 因为它看起来很奇怪 我
  • 我的简短 C 代码中的小错误。为什么?

    我不明白为什么这对 90 的输入有效 但对其他输入无效 它的目的是告诉您可以找回多少硬币 大多数测试金额都可以正常工作 但如果您输入 4 20 或 4 20 美元 它会返回 23 个硬币 应该是 18 个硬币 16 个 25 美分硬币和 2
  • 设置 XY 图上点标签的格式

    中描述的方法Androidplot教程不适用于 API 版本 1 1 0 没有方法setPointLabeler 在班上线和点渲染器 该文档适用于非常旧版本的 Androidplot 该方法已移至 LineAndPointFormatter
  • Java 1.8.20 编译器错误

    以下代码块在 1 8 11 中编译得很好 但在 1 8 20 中抛出错误 private static String calculateSyntheticOrderTypePrice FluentIterable
  • 使用 DataTables,如何指定要搜索的 内的元素

    我正在使用 jquery DataTables 并且我有一个包含单元格的表格 每个单元格 td 包含一个 span 和一个隐藏的 span td
  • 如何删除字符串上的重音符号? [复制]

    这个问题在这里已经有答案了 可能的重复 如何从 NET 中的字符串中删除变音符号 重音符号 我有以下字符串 我需要将其转换为 aeiou 我怎样才能实现它 我不需要比较 我需要新的字符串来保存 不是重复的如何从 NET 中的字符串中删除变音
  • C++中如何在字符串中每N个字符插入一个字符

    我怎样才能插入一个char角色变成string恰好在 1 个字符之后 我需要插入 进入 每隔一个字符之后的字符串 换句话说 C Tokens all around 变成 T o k e n s a l l a r o u n d 不 那不是
  • Guice @Nullable 注释

    在我的服务中 我有一个受保护的构造函数 Inject和参数之一 提供者 Nullable 任何想法为什么我得到 com google inject CreationException Guice creation errors 1 No i
  • 将标志存储在数据库中

    在我的应用程序中 我希望用户选择他的工作日 然后将它们存储在数据库中 当然 我的应用程序将处理用户的数据 例如 今天是特定用户的工作日吗 今天应该工作的用户是谁 等等 我的问题是 这样做的最佳实践是什么 我应该使用 用户表中的位掩码字段 通
  • 使用模块中除一个变量之外的所有变量 - 是否有“仅”的反义词?

    我有一个带有全局变量的模块 里面有很多变量 对于特定的子例程 我想使用其中除 1 之外的所有变量 我可以做到这一点的一种方法是 use Global Variables only item1 item50 item52 item100 但是
  • 由于目录权限,Node.js 部署在 Amazon Elastic Beanstalk 上失败

    我尝试使用命令行工具在 Elastic Beanstalk 上安装一个简单的 Node js 应用程序 在我的 git 存储库上运行命令 eb deploy 部署我的 git 存储库的内容 它部署良好 但应用程序的运行状况为红色 如果我查看
  • 拒绝访问网站文件夹

    我看过几个网站 例如http www website com images pic001 jpg当我尝试访问时http www website com images 被禁止 这正是我想要保护我的文件夹免受好奇的原因 我怎样才能做到这一点 添
  • 以编程方式访问货币汇率[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 我正在建立一个在线订购系统 但我在澳大利亚 对于国际客户 我想以美元或欧元显示价格 这样
  • SwiftUI · 后台计时器在模拟器上有效,但在真实设备上无效

    我正在尝试构建一个计时器 当应用程序处于后台甚至屏幕被锁定时 该计时器会继续倒计时 计时器达到 0 后 应发送通知 到目前为止 它可以在模拟器上运行 但不能在真实设备 iPhone X 运行 iOS 13 5 1 上运行 当进入后台时 任务
  • NetworkX - 有没有办法根据节点权重缩放图中节点的位置?

    我构建了一个显示图表的应用程序 并在幕后使用 NetworkX 来存储我的图表 每个节点都有一个大小 我想根据这些大小更改节点位置 例如 大 节点周围的空间比 小 节点更多 有什么算法 方法 库 其他想法可以帮助我做到这一点吗 谢谢 阿迪
  • 无法结束BackgroundTask:不存在带有标识符的后台任务,或者它可能已经结束

    我正在使用后台任务在后台运行计时器来更新用户的位置 它被声明为 UIBackgroundTaskIdentifier bgTask 在头文件中 并初始化为 bgTask UIBackgroundTaskInvalid 但我仍然在 gdb 中
  • 在 facebook connect 中,如何检查用户是否是我的 Facebook 页面的粉丝?可以追踪吗?

    我正在尝试确定用户是否是 Facebook 粉丝 我加载 facebook JS 库并初始化 FB RequireFeatures XFBML Connect Api function FB init my api key xd recei
  • 将使用 Flex 4 SDK 编译的 Flex 模块加载到使用 Flex 3.5 编译的应用程序中

    我正在为需要 Flex 4 功能的应用程序开发一项功能 由于应用程序从 Flex 3 5 到 4 0 的一些迁移问题 我决定将此功能实现为使用 Flex 4 0 编译的模块 理论上 应用程序将保持在 Flex 3 5 中编译 并在需要时加载
  • C# / WPF 从另一个类中创建的另一个线程更新 UI

    我有嵌入式 C 背景 正在开发我的第一个 C 应用程序 但我在这方面遇到了障碍 而且我的研究没有成功 所以我想我应该在这里问 到目前为止 简单的应用程序 我有一个 MainWindow 除了一堆其他东西之外 还可以在单 击按钮时启动 TCP