C#多线程与跨线程访问界面控件的方法

yizhihongxing

下面是 C# 多线程与跨线程访问界面控件的方法完整攻略:

1. C# 多线程基础

在 C# 中,多线程的基本实现是通过 System.Threading 命名空间下的类来实现的。常用的类有:

  • Thread:表示一个单独的线程。
  • ThreadPool:表示一个线程池,它包含了多个预先创建的线程。
  • Task:表示一个异步操作。

下面展示一个创建并运行线程的示例代码:

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        Thread newThread = new Thread(Worker);
        newThread.Start();
        Console.ReadLine();
    }

    static void Worker()
    {
        Console.WriteLine("Thread started.");
        Thread.Sleep(1000);
        Console.WriteLine("Thread ended.");
    }
}

上述代码会创建一个新线程并在该线程中运行 Worker 方法。Worker 方法简单地等待 1 秒钟后输出一段文本。在主线程中,我们等待用户按下回车键后才结束程序运行。

2. 跨线程访问控件

由于 C# 中 UI 控件是运行在主线程中的,因此我们不能直接在非主线程中访问它们。如果我们在非主线程中提供了一些 UI 操作的代码,尝试去更新 UI 控件的状态,将会抛出异常。因此,我们需要使用跨线程访问控件的方法来避免这个问题。

有多种方法可以实现跨线程访问控件,在这里我们介绍两种常见的方法。

2.1 Control.Invoke

Control.Invoke 方法可以在 UI 线程队列中执行指定的委托。下面是一个例子:

using System;
using System.Threading;
using System.Windows.Forms;

class Program
{
    static Label label;
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Form form = new Form();

        label = new Label();
        label.Text = "Starting...";
        label.Dock = DockStyle.Fill;
        form.Controls.Add(label);

        Thread newThread = new Thread(Worker);
        newThread.Start();

        Application.Run(form);
    }

    static void Worker()
    {
        DoUiWork("Thread started.");

        Thread.Sleep(1000);

        DoUiWork("Thread ended.");
    }

    delegate void StringArgReturningVoidDelegate(string text);

    static void UpdateLabel(string text)
    {
        label.Text = text;
    }

    static void DoUiWork(string text)
    {
        if (label.InvokeRequired)
        {
            StringArgReturningVoidDelegate del = new StringArgReturningVoidDelegate(UpdateLabel);
            label.Invoke(del, new object[] { text });
        }
        else
        {
            UpdateLabel(text);
        }
    }
}

在上述例子中,我们将一个标签加入了窗口中。在 Worker 方法中,我们通过 DoUiWork 方法来更新 label 对象的 Text 属性。该方法首先检查是否在 UI 线程中,如果在 UI 线程中,它会直接执行 UpdateLabel 方法,否则会通过 Control.Invoke 方法在 UI 线程中执行 UpdateLabel。使用 Control.Invoke 的时候需要注意:如果 UI 线程已经被阻塞,则调用 Control.Invoke 会导致死锁。

2.2 Control.BeginInvoke

Control.BeginInvoke 方法可以使一个委托异步地在 UI 线程中执行。与 Control.Invoke 不同,Control.BeginInvoke 不会阻塞当前线程。

using System;
using System.Threading;
using System.Windows.Forms;

class Program
{
    static Label label;
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Form form = new Form();

        label = new Label();
        label.Text = "Starting...";
        label.Dock = DockStyle.Fill;
        form.Controls.Add(label);

        Thread newThread = new Thread(Worker);
        newThread.Start();

        Application.Run(form);
    }

    static void Worker()
    {
        DoUiWork("Thread started.");

        Thread.Sleep(1000);

        DoUiWork("Thread ended.");
    }

    delegate void StringArgReturningVoidDelegate(string text);

    static void UpdateLabel(string text)
    {
        label.Text = text;
    }

    static void DoUiWork(string text)
    {
        if (label.InvokeRequired)
        {
            StringArgReturningVoidDelegate del = new StringArgReturningVoidDelegate(UpdateLabel);
            label.BeginInvoke(del, new object[] { text });
        }
        else
        {
            UpdateLabel(text);
        }
    }
}

上述代码与前一个例子很相似,唯一的不同在于我们换用了 Control.BeginInvoke 方法来切换到 UI 线程。具体用法也基本相同,我们通过 DoUiWork 方法来更新 label 对象的 Text 属性,方法中首先检查是否在 UI 线程中。如果在 UI 线程中,它会直接执行 UpdateLabel 方法,否则会通过 Control.BeginInvoke 方法在 UI 线程中异步执行 UpdateLabel。注意:使用 Control.BeginInvoke 的时候,我们不知道委托什么时候会被执行,因此需要小心使用。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#多线程与跨线程访问界面控件的方法 - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • C#在复杂多线程环境下使用读写锁同步写入文件

    使用读写锁同步写入文件可以在复杂多线程环境下有效地保证数据的一致性和并发性。下面是使用C#实现该功能的攻略: 1.了解读写锁 读写锁是一种在多线程环境下保证数据一致性和并发性的解决方案,其主要思想为:在读多写少的情况下,允许多个线程同时读取数据,但只允许一个线程写入数据。当有线程在写入数据时,其他线程无法读取或写入数据。 2.创建读写锁对象 C#提供了读写锁…

    C# 2023年5月15日
    00
  • c#语言程序构建基块

    下面是关于C#语言程序构建基块的详细讲解攻略。 1. 前置知识 在学习C#语言程序构建基块之前,需要先掌握以下基础知识: C#语言基础语法 常用数据类型和变量定义 控制流语句和循环语句 函数和方法 面向对象编程基础概念 如果你还没有掌握以上基础知识,建议先学习C#语言基础课程。 2. 程序构建基块 程序构建基块,也称为程序库,是指封装了特定功能的代码模块,可…

    C# 2023年5月15日
    00
  • C#实现五子棋游戏

    C#实现五子棋游戏——完整攻略 1. 整体思路 五子棋游戏是一种基于棋盘的二人策略游戏,玩家需要在棋盘上交替落子,最先形成连续五个同色棋子的一方获胜。从整体上看,C#实现五子棋游戏需要实现如下基本功能: 初始化游戏界面:包括生成棋盘、设置初始状态等。 点击落子事件:点击棋盘上某个交叉点,将当前玩家的棋子落在该点上。 判定胜负:每次落子后,需要判断当前状态是否…

    C# 2023年6月7日
    00
  • C# Winform中如何绘制动画示例详解

    下面我就来详细讲解一下“C# Winform中如何绘制动画示例详解”的完整攻略。 1. 背景知识 在开始讲解动画绘制之前,有一些必要的背景知识需要了解: C#是一种基于面向对象的编程语言,常用于开发Windows桌面应用程序。 Winform是C#中常用的Windows桌面应用程序框架,可以方便地进行用户界面设计与开发。 在Winform应用程序中,我们可以…

    C# 2023年6月6日
    00
  • C# javaScript函数的相互调用

    C#和JavaScript都是常用的编程语言,在Web开发中,经常需要对这两种语言进行交互。通过C#代码调用JavaScript函数可以为Web程序添加更多的交互性和动态性。同时,JavaScript函数也可以调用C#代码来实现更为复杂的功能,增强Web程序的性能和灵活性。 下面是“C#和JavaScript函数相互调用”的完整攻略: C#调用JavaScr…

    C# 2023年6月8日
    00
  • C#编程获取客户端计算机硬件及系统信息功能示例

    下面是详细讲解“C#编程获取客户端计算机硬件及系统信息功能示例”的完整攻略: 介绍 在开发过程中,我们有时需要获取客户端计算机的硬件和系统信息来帮助我们更好地处理业务逻辑。这个过程可以用C#编程来实现,这篇攻略将介绍如何通过C#获取客户端计算机的硬件和系统信息。 获取硬件信息 要获取客户端计算机的硬件信息,可以使用System.Management命名空间中…

    C# 2023年6月7日
    00
  • .NET/C#利用反射调用含ref或out参数的方法示例代码

    下面是详细的攻略: 1. 了解反射 反射是一种在运行时获取类型信息的机制。使用反射可以在运行时获取如类的名称、属性的名称、方法的名称等信息。通过反射,可以在运行时动态地加载程序集,创建实例并调用其成员。 2. 获取类型信息 在利用反射调用含ref或out参数的方法之前,需要先获取到该方法所属的类型的信息。我们通过以下代码来获取类型信息: Type type …

    C# 2023年5月31日
    00
  • ASP.NET MVC 5使用X.PagedList.Mvc进行分页教程(PagedList.Mvc)

    下面我将为您详细讲解“ASP.NET MVC 5使用X.PagedList.Mvc进行分页教程(PagedList.Mvc)”的完整攻略。首先,我们需要了解一下PagedList.Mvc和X.PagedList.Mvc分别是什么。 PagedList.Mvc是用于ASP.NET MVC的基于.NET标准库的分页程序包。它使用标准HTML实现了分页链接,并通过…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部