winform异步加载

 

1. 使用asyncawait关键字

首先,在你的方法前加上async关键字,然后在调用长时间运行的方法前使用await关键字。例如,如果你有一个长时间运行的方法LoadDataAsync(),你可以这样调用它:

复制代码
public async void LoadDataButton_Click(object sender, EventArgs e)
{
    await Task.Run(() => LoadData());
    UpdateUI();
}
 
private void LoadData()
{
    // 模拟长时间运行的任务
    Thread.Sleep(5000); // 例如,加载数据可能需要一些时间
}
 
private void UpdateUI()
{
    // 更新UI元素,例如设置Label的文本
    this.statusLabel.Text = "数据加载完成";
}
复制代码

2. 使用BackgroundWorker

BackgroundWorker类提供了一个简单的方式来执行长时间运行的任务,而不会冻结UI线程。你可以在后台工作项完成后更新UI。详细参考,BackgroundWorker它通过事件驱动的方式,允许在后台线程中执行耗时操作,并通过事件回调更新UI,从而避免

直接从非UI线程更新UI可能引起的线程安全问题。不需要begininvoke。

复制代码
private void LoadDataButton_Click(object sender, EventArgs e)
{
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += LoadData;
    worker.RunWorkerCompleted += UpdateUI;
    worker.RunWorkerAsync();
//worker.RunWorkerAsync(object argument)//可传参数重置 }
private void LoadData(object sender, DoWorkEventArgs e) { // 模拟长时间运行的任务 Thread.Sleep(5000); // 例如,加载数据可能需要一些时间 } private void UpdateUI(object sender, RunWorkerCompletedEventArgs e) { this.statusLabel.Text = "数据加载完成";//不用使用begininvoke吗? }

精简写法:
1
2
3
4
5
6
7
8
9
10
private void LoadDataAsync()
{
    // 创建BackgroundWorker实例
    BackgroundWorker worker = new BackgroundWorker();
    // 设置后台任务的执行函数
    worker.DoWork += (sender, e) =>
    {
        // 在这里执行数据加载操作
        // ...
    };<br>  //进度条更新
    worker.ProgressChanged += (sender, e) => {
      // 在这里更新 UI,显示进度条等。使用 e.ProgressPercentage 获取进度值。
      Console.WriteLine($"Progress: {e.ProgressPercentage}%");
    };
1
2
3
4
5
6
7
8
9
    // 设置后台任务完成后的回调函数
    worker.RunWorkerCompleted += (sender, e) =>
    {
        // 在这里处理数据加载完成后的逻辑
        // ...
    };
    // 启动后台任务
    worker.RunWorkerAsync();
}
 
复制代码

注意:使用thread类也可以实现。

BeginInvoke方法用于异步地将一个委托封装的操作发送到UI线程的消息队列中。这样,即使是在后台线程中,也可以安全地更新UI控件。BeginInvoke方法不会阻塞当前线程,而是将任务排队,待UI线程空闲时执行。

复制代码
private void button1_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(StartSomeWork));
            thread.IsBackground = true;
            thread.Start();
        }

        private void StartSomeWork()
        {
            if (this.InvokeRequired)
            {
                BeginInvoke(new EventHandler(RunsOnWorkerThread), null);
            }
            else
            {
                RunsOnWorkerThread(this, null);
            }
        }

        private void RunsOnWorkerThread(object sender, EventArgs e)
        {
            Thread.Sleep(2000);
            label1.Text = System.DateTime.Now.ToString();
        }
复制代码

 

3. 使用TaskTask.Run结合Control.InvokeControl.BeginInvoke

如果你需要在异步操作中更新UI,可以使用InvokeBeginInvoke方法确保UI更新在UI线程上执行。

复制代码
private async void LoadDataButton_Click(object sender, EventArgs e)
{
    await Task.Run(() => LoadData());
    this.Invoke((MethodInvoker)delegate { UpdateUI(); });
}
 
private void LoadData()
{
    // 模拟长时间运行的任务
    Thread.Sleep(5000); // 例如,加载数据可能需要一些时间
}
 
private void UpdateUI()
{
    this.statusLabel.Text = "数据加载完成";
}
复制代码

4. 使用asyncawait结合InvokeBeginInvoke(推荐用于UI更新)

如果你希望在异步方法中直接更新UI,可以在调用UI相关代码前使用InvokeBeginInvoke

private async void LoadDataButton_Click(object sender, EventArgs e)
{
    await Task.Run(() => LoadData()); // 后台加载数据
    this.Invoke((MethodInvoker)delegate { this.statusLabel.Text = "数据加载完成"; }); // UI线程更新UI
}

总结:

选择哪种方法取决于你的具体需求和偏好。对于简单的异步操作和UI更新,使用asyncawait结合Invoke通常是简单且有效的。对于更复杂的后台任务处理,使用BackgroundWorker可能更合适。而Task.Run结合适当的线程同步机制(如Invoke)提供了灵活

的控制方式。

posted @   love/coder  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示