从目前已经在项目中工作将近一个月来的情况来看,凡是费时的操作,基本上都要用到多线程的等待窗体、进度提示窗体等实时显示动态的进度信息。而如果直接在主线程的窗体上实时更新信息,就会造成更新太快或者太慢而出现的进程假死现象。为了缓解这些情况,本文就参考一些文章,把他们的智慧总结于此。希望对大家有所帮助。
一、多线程中创建等待窗体
在winform程序开发中,计算机经常会执行一些比较耗时的任务,如大量数据的查询操作、较为复杂的业务处理等,这些任务往往需要耗时几秒到几十秒钟的时间,在这些任务执行期间winform程序窗体不再响应任何鼠标和键盘事件,出现假死状态,用户体验很差。
一个比较好的解决办法是,在这些任务执行期间在界面前端显示一个等待窗体,告诉用户任务正在执行中。
1.1 开发等待窗体
窗体中有一个PictureBox控件和两个Lable控件,PictureBox控件的Image属性为一张动态图片。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Threading; using NavManager.Common; namespace NavManager.Utils { public partial class WaitForm : Form { public WaitForm() { InitializeComponent(); SetText(""); } private delegate void SetTextHandler(string text); public void SetText(string text) { if (this.label2.InvokeRequired) { this.Invoke(new SetTextHandler(SetText), text); } else { this.label2.Text = text; } } } }
等待窗体源码
1.2 提供访问等待窗体的接口
编写类WaitFormService
using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Windows.Forms; namespace NavManager.Utils { /// <summary> /// Using Singleton Design Pattern /// </summary> public class WaitFormService { public static void CreateWaitForm() { WaitFormService.Instance.CreateForm(); } public static void CloseWaitForm() { WaitFormService.Instance.CloseForm(); } public static void SetWaitFormCaption(string text) { WaitFormService.Instance.SetFormCaption(text); } private static WaitFormService _instance; private static readonly Object syncLock = new Object(); public static WaitFormService Instance { get { if (WaitFormService._instance == null) { lock (syncLock) { if (WaitFormService._instance == null) { WaitFormService._instance = new WaitFormService(); } } } return WaitFormService._instance; } } private WaitFormService() { } private Thread waitThread; private WaitForm waitForm; public void CreateForm() { if (waitThread != null) { try { waitThread.Abort(); } catch (Exception) { } } waitThread = new Thread(new ThreadStart(delegate() { waitForm = new WaitForm(); Application.Run(waitForm); })); waitThread.Start(); } public void CloseForm() { if (waitThread != null) { try { waitThread.Abort(); } catch (Exception) { } } } public void SetFormCaption(string text) { if (waitForm != null) { try { waitForm.SetText(text); } catch (Exception) { } } } } }
WaitFormService Class Code
1.3 使用WaitFormService提供的接口
try { WaitFormService.CreateWaitForm(); Assembly asmb = Assembly.GetExecutingAssembly(); Object obj = asmb.CreateInstance(className); Form frm = obj as Form; this.ShowMenu(frm); WaitFormService.CloseWaitForm(); } catch (Exception ex) { WaitFormService.CloseWaitForm(); }
接口的使用
二、透明的数据加载进度条
建立一个公用的进度条控件,每次加载较慢的时候使用以改进用户体验。通过启用新线程的方式来进行调用。
步骤如下:
(1)建立一个单独的窗体,包含一个进度条控件。
设置进度条的Style为ProgressBarStyle.Marquee;
增加一属性(LoadCompleted)标示加载是否完成。
(2)在其它窗体中通过开启新线程进行调用。
public partial class UcLoadData_ShowMarqueeProcess : UserControl { public static FrmMarqueeProcess xf; public static event EventHandler onLoadFinished; public UcLoadData_ShowMarqueeProcess() { InitializeComponent(); } private void btnFill_Click(object sender, EventArgs e) { int iEnd = 10000; Thread t = new Thread(new ThreadStart(ShowProcess)); t.Start(); for (int i = 0; i < iEnd; i++) { string strContent = string.Format("this is the {0}th record", i); this.lstContent.Items.Add(strContent); } onLoadFinished += new EventHandler(LoadFinish); if (onLoadFinished != null) onLoadFinished.Invoke(sender, e); while (!xf.LoadCompleted) Application.DoEvents(); t.Abort(); } private static void ShowProcess() { xf = new FrmMarqueeProcess(); xf.ShowDialog(); } private static void LoadFinish(object sender, EventArgs e) { xf.LoadCompleted = true; } }
透明进度条源码
运行结果如下:
参考文章
1. 飘落纸飞机,C# winform 多线程中创建等待窗体,2011。
时间: 2024-12-10 19:12:03