C# GUI_Async_await异步报告
// .net8环境 Winform
namespace GUI_Async_await异步报告_供参考_
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
progressBar2.Value = 0;
progressBar3.Value = 0; // 进度条 恢复初始值. 不然Value的值 一直是100.
sync(); // 同步方法
}
private async void button2_Click(object sender, EventArgs e) // 注意: 使用 async 的方法需要在 async 方法内调用.
{
progressBar1.Value = 0;
progressBar2.Value = 0;
progressBar3.Value = 0; // 进度条 恢复初始值. 不然Value的值 一直是100.
progressBar2.Value = await Async(); // 返回执行结果, 注意, 并不是执行过程. 这样的异步方法不会卡在UI界面. 这样的方法适合在后台处理, 直到处理完成再报告结果.
}
private async void button3_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
progressBar2.Value = 0;
progressBar3.Value = 0; // 进度条 恢复初始值. 不然Value的值 一直是100.
await CallBack(); // 执行异步过程
}
private async void button4_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
progressBar2.Value = 0;
progressBar3.Value = 0; // 进度条 恢复初始值. 不然Value的值 一直是100.
await Step_Report(); // 阶梯式进度条. 如果需要快速调用异步过程方法, 可以试着参考该方法.
}
async void More_Async() // 多个异步方法组合处理
{
int[] ints = await Task.WhenAll(Async(), Async()); // 返回一组任务组, 如果任务组都完成则都返回
Task<int> Int = await Task.WhenAny(Async(), Async()); // 返回优先完成的任务
// 注意:如果直接使用方法返回,是无法正确获取任务结果的。 如: textBox1.Text += Async().IsCompleted;
}
// 同步方法
void sync()
{
for (int x = 0; x < 101; x++) { Thread.Sleep(100); progressBar1.Value = x; }
}
// 异步方法
// 如果需要了解到Task方法是否完成, 就需要Task的返回结果.
// 当然也可以 async void 不需要返回值, 但是这样就不知道执行结果了. 还是根据需求设计.
async Task<int> Async()
{
int result = 0;
await Task.Run(() =>
{
for (int x = 0; x < 101; x++)
{
Thread.Sleep(10); // 等待0.1秒
result = x; // 需要知道Task是否完成所以需要一个值来返回.
}
});
return result; // 返回结果
}
// 异步过程, 会将后台处理的过程显示在UI界面上, 而不影响UI.
// 需要使用到 IProgress 泛型接口 和 Progress 泛型类,
async Task Async_Timeout(IProgress<int> progress) // 这里Task没有指定类型, 默认为null.
/* 需要注意的是,IProgress<T>.Report 方法可以是异步的。这意味着真正报告进度之前,Async_Timeout 方法会继续运行。
* 基于这个原因,最好把 T 定义为一个不可变类型,或者至少是值类型。
* 如果 T 是一个可变的引用类型,就必须在每次调用 IProgress<T>.Report 时, 创建一个单独的副本。*/
{
for (int x = 0; x < 101; x++)
{
await Task.Delay(10); // Task.Delay 拥有返回值
progress.Report(x); // progress 只有一个Reprot报告的方法.
}
}
async Task CallBack()
{
var progress = new Progress<int>(); // 使用 Progress 泛型类
/* Progress<T> 会在创建时捕获当前上下文,并且在这个上下文中调用回调函数。这意味着,
* 如果在 UI 线程中创建了 Progress<T>,就能在 Progress< T > 的回调函数中更新 UI,即使异
* 步方法是在后台线程中调用 Report 的。*/
progress.ProgressChanged += (sender, y) => { progressBar3.Value = y; change_progress(y); }; // 实例化的 Progress 只有一个事件方法, (sender, y) 括号内两个的参数名可以自定义, 但是传参的是 第二个参数
// var progress = new Progress<int>(change_progress); // 如果ProgressChanged 太麻烦, 可以使用构造Progress函数填入一个方法即可, 这个方法不需要填入参数, 因为该参数默认指定为Async_Progress的返回值, 但是只能指定一个方法
await Async_Timeout(progress);
}
void change_progress(int y) // 仅能被CallBack方法调用.
{
progressBar1.Value = y;
progressBar2.Value = y;
}
async Task Step_Report() // 阶梯式进度条
{
for (int x2 = 0; x2 < 101; x2 += 20)
{
progressBar3.Value = x2;
if (x2 >= 100) { break; } // 最后进度条完成 则所有进度条都完成
for (int x1 = 0; x1 < 101; x1 += 5)
{
progressBar2.Value = x1;
for (int x = 0; x < 101; x += 10) { await Task.Delay(10); progressBar1.Value = x; }
}
}
}
}
}
## 执行过程
文章编写or整理的内容由作者完成,引用or参考会给出原文链接。