WinForm中UI假死的解决方法 您所在的位置:网站首页 ipadpro105怎么关闭高频刷新 WinForm中UI假死的解决方法

WinForm中UI假死的解决方法

2024-01-15 19:15| 来源: 网络整理| 查看: 265

1、前言

WinForm中的UI假死其实是个老生常谈的问题了,但最近还是很多同志问该如何解决,今天就来说明一下。测试程序界面如下图所示:一个Button和一个ProgressBar。

在这里插入图片描述

2、主线程的阻塞和UI更新问题

先看一个简单的例子:

using System; using System.Threading; using System.Windows.Forms; namespace App { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btn_Click(object sender, EventArgs e) { progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Style = ProgressBarStyle.Blocks; progressBar1.Step = 1; progressBar1.Value = 0; int max = progressBar1.Maximum; for (int i = 1; i public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btn_Click(object sender, EventArgs e) { progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Style = ProgressBarStyle.Blocks; progressBar1.Step = 1; progressBar1.Value = 0; Task task = Task.Run(() => { int max = progressBar1.Maximum; for (int i = 1; i public delegate void UpdateProgressBarDelegate(int num); public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btn_Click(object sender, EventArgs e) { progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Style = ProgressBarStyle.Blocks; progressBar1.Step = 1; progressBar1.Value = 0; Task task = Task.Run(() => { UpdateProgressBar(); }); } private void UpdateProgressBar() { int max = progressBar1.Maximum; for (int i = 1; i if (progressBar1.InvokeRequired) { progressBar1.Invoke(new UpdateProgressBarDelegate(UpdateProgressBarCallback), new object[] { num }); } else { progressBar1.Value = num; } } } } 4、使用BackgroundWorker解决界面卡死问题

WinForm中的BackgroundWorker组件也可以很好地解决界面卡死问题,如下图所示:

在这里插入图片描述

BackgroundWorker组件的核心就是DoWork、ProgressChanged、ProgressChanged三个事件,代码如下:

using System; using System.Threading; using System.Windows.Forms; namespace App { public partial class MainForm : Form { public MainForm() { InitializeComponent(); backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = true; } private void btn_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy) { return; } progressBar1.Minimum = 0; progressBar1.Maximum = 100; progressBar1.Style = ProgressBarStyle.Blocks; progressBar1.Step = 1; progressBar1.Value = 0; backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { int max = progressBar1.Maximum; for (int i = 1; i progressBar1.Value = e.ProgressPercentage; } private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) { MessageBox.Show("完成"); } } } 5、使用async、await解决界面卡死问题

上面提到的Delegate和BackgroundWorker组件主要是针对UI的更新问题,其实还有一种情况也会造成UI的卡死,那就是某些耗时操作。先来看一段代码:

using System; using System.Threading; using System.Windows.Forms; namespace App { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btn_Click(object sender, EventArgs e) { string message = GetMessage(); MessageBox.Show(message); } private string GetMessage() { Thread.Sleep(5000); return "Hello World"; } } }

在上面的代码中,GetMessage方法模拟了一个耗时操作,运行程序,发现UI假死,界面无法拖动,此时就可以考虑使用async和await来解决。代码如下:

using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace App { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private async void btn_Click(object sender, EventArgs e) { string message = await GetMessageAsync(); MessageBox.Show(message); } private async Task GetMessageAsync() { return await Task.Run(() => { Thread.Sleep(5000); return "Hello World"; }); } } } 6、使用Task解决界面卡死问题

对于一些老项目,比如.NET 4.0版本下的代码,开发者无法使用async、await,此时就可以考虑使用Task来实现。代码如下:

using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace App { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btn_Click(object sender, EventArgs e) { string message = ""; Task task = Task.Factory.StartNew(() => { message = GetMessage(); }) .ContinueWith(t => { MessageBox.Show(message); }); } private string GetMessage() { Thread.Sleep(5000); return "Hello World"; } } } 7、结语

本文主要介绍了WinForm中的UI假死解决方案。在实际开发中,合理使用多线程可以有效提高界面的人机交互体验。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有