实验目标和实验内容:
- 掌握C#线程基本概念;
- 掌握C#线程控件;
- C#使用委托实现多线程调用窗体。
线程解释见:https://blog.csdn.net/m0_74749240/article/details/139408891
实现:
(1).控件:group Box,text Box,check Box,label,botton,richtextbox
注意:文本区1和文本区2的底层是容器groupbox,而白色幕布是richtextbox
(2).具体代码实现:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 线程
{
// 窗体的主类
public partial class Form1 : Form
{
// 用于逐个字符写入文本的委托
public delegate void WriteTextDelegate(char ch);
public WriteTextDelegate writeText;
// 构造函数,初始化窗体组件
public Form1()
{
InitializeComponent();
}
// 按钮点击事件处理方法
private void button1_Click(object sender, EventArgs e)
{
// 获取文本框中的文本
string text = textBox1.Text;
// 启动一个新线程执行 CopyText 方法
Thread thread = new Thread(() => CopyText(text));
thread.Start();
}
// 逐个字符地将文本复制到 RichTextBox
private void CopyText(string text)
{
// 检查复选框1是否被选中
if (checkBox1.Checked)
{
// 将文本的每个字符添加到 richTextBox1
foreach (char ch in text)
{
AppendCharSafe(richTextBox1, ch);
}
}
// 模拟一些延迟
Thread.Sleep(1000);
// 检查复选框2是否被选中
if (checkBox2.Checked)
{
// 将文本的每个字符添加到 richTextBox2
foreach (char ch in text)
{
AppendCharSafe(richTextBox2, ch);
}
}
}
// 安全地将字符添加到 RichTextBox
private void AppendCharSafe(RichTextBox richTextBox, char ch)
{
// 检查是否需要跨线程调用
if (richTextBox.InvokeRequired)
{
// 使用 Invoke 在 UI 线程上执行委托
richTextBox.Invoke(new MethodInvoker(delegate
{
richTextBox.AppendText(ch.ToString() + Environment.NewLine);
}));
}
else
{
// 如果在 UI 线程上,则直接添加字符
richTextBox.AppendText(ch.ToString() + Environment.NewLine);
}
}
// 可选的处理复选框1状态改变的事件
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// 可根据需要处理该事件
}
// 可选的处理复选框2状态改变的事件
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
// 可根据需要处理该事件
}
// 可选的处理 richTextBox1 文本改变的事件
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
// 可根据需要处理该事件
}
// 可选的处理 label1 点击事件
private void label1_Click(object sender, EventArgs e)
{
// 可根据需要处理该事件
}
// 可选的处理 groupBox1 进入事件
private void groupBox1_Enter(object sender, EventArgs e)
{
// 可根据需要处理该事件
}
}
}
运行结果:
小结及重难点:
小结
这段代码是一个Windows Forms应用程序,它通过两个BackgroundWorker控件实现了后台任务处理,分别将文本框中的字符逐个输出到两个富文本框中。用户可以通过选择两个复选框来控制哪个后台任务被启动,并且每个字符之间有一秒的延迟。
重难点
-
多线程编程:
- 使用BackgroundWorker实现后台任务,以防止主线程(UI线程)被阻塞,保证了用户界面的响应性。
- 通过
RunWorkerAsync
方法启动后台任务,并使用DoWork
事件处理程序定义具体的后台操作。
-
进度报告和UI更新:
- 在后台任务中,通过
ReportProgress
方法报告进度,传递当前处理的字符。 - 在
ProgressChanged
事件处理程序中,通过访问UserState
属性获取传递的字符并更新富文本框。 - 需要注意的是,跨线程操作UI控件必须通过适当的方法进行,否则会引发异常。BackgroundWorker自动处理了这种情况。
- 在后台任务中,通过
-
线程同步问题:
- 尽管代码没有明显涉及线程同步,但要注意在多线程环境下共享资源时可能会遇到的同步问题。这里每个BackgroundWorker独立操作不同的UI控件,因此没有出现资源竞争的问题。
-
延迟模拟:
- 使用
Thread.Sleep
模拟处理延迟。虽然在这里是为了演示效果,但在实际应用中应避免在DoWork
中使用Thread.Sleep
,因为这会阻塞后台线程。可以考虑其他更优雅的异步方式来实现延迟效果。
- 使用
-
用户体验:
- 通过复选框选择不同的后台任务,提供了简单的用户交互方式。
- 在点击按钮后,根据复选框的选择启动相应的后台任务,动态控制后台任务的执行。
详细解释
-
Form1 类:
- 这是主窗体类,包含了处理用户界面和后台线程操作的逻辑。
-
WriteTextDelegate:
- 定义了一个委托,用于逐个字符地写入文本。
-
Form1 构造函数:
- 初始化窗体组件。
-
button1_Click:
- 处理按钮点击事件,获取文本框中的文本,并启动一个新线程执行
CopyText
方法。
- 处理按钮点击事件,获取文本框中的文本,并启动一个新线程执行
-
CopyText:
- 根据复选框的选中状态,逐个字符地将文本添加到相应的
RichTextBox
控件中。 - 使用
Thread.Sleep
模拟一些延迟。
- 根据复选框的选中状态,逐个字符地将文本添加到相应的
-
AppendCharSafe:
- 这是一个辅助方法,确保在正确的线程上安全地操作
RichTextBox
控件。 - 如果当前线程不是创建控件的线程,使用
Invoke
方法在UI线程上执行代码。
- 这是一个辅助方法,确保在正确的线程上安全地操作
-
可选的事件处理方法:
checkBox1_CheckedChanged
、checkBox2_CheckedChanged
、richTextBox1_TextChanged
、label1_Click
和groupBox1_Enter
方法是可选的,可以根据需要实现具体的逻辑。