等待对话框实现

在使用Winform开发程序时,经常会碰到一些耗时操作,如果不加处理的话,第一用户体验不好,第二如果操作会造成程序卡死。所以在这类情况下就要使用进度框来使程序在处理的同时显示一个进度框,效果截图如下:

如上这种方式显示进度框。但是显示进度框的时候也要同时阻断用户对窗体的操作,所以当进度框显示时可使用IMessageFilter的方式来过滤窗体消息,这样就可以达到类似模态对话框的目的,而进度对话框的调用则使用BackgroundWorker来完成,具体的代码如下:

WaitDialog.cs

using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CommonControl.WaitDialog
{
    /// <summary>
    /// 等待窗体
    /// </summary>
    internal partial class WaitDialog : Form
    {
        /// <summary>
        /// 计时器,用来步进进度条
        /// </summary>
        private Timer timer;

        private WaitDialog()
        {
            InitializeComponent();
        }

        public WaitDialog(string strTip) : this()
        {
            lblWaitTip.Text = strTip;
            timer = new Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 1000;
            timer.Start();
        }

        /// <summary>
        /// 计时方法,用来步进进度条
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void timer_Tick(object sender, EventArgs e)
        {
            pgbWaitTip.Value = (pgbWaitTip.Value + 5) % pgbWaitTip.Maximum;
        }

        /// <summary>
        /// 当触发等待窗体结束时关闭等待窗体
        /// </summary>
        public void WaitDialogEnd()
        {
            this.Invoke(new Action(delegate{
                this.Close();
            }));
        }

        /// <summary>
        /// 窗体关闭方法
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            this.Close();
        }
    }
}

上面使用一个Timer来在窗体创建后每隔1秒来使进度条增加5,并循环执行。

WaitUtility.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace CommonControl.WaitDialog
{
    /// <summary>
    /// 等待窗体结束委托
    /// </summary>
    public delegate void WaitDialogEndHandle();

    /// <summary>
    /// 等待对话框操作类
    /// </summary>
    public class WaitUtility
    {
        #region 使用单例模式来使用等待对话框

        /// <summary>
        /// 同步锁
        /// </summary>
        private static object objLock = new object();

        private static WaitUtility _Instance;

        /// <summary>
        /// 等待对话框操作实体类
        /// </summary>
        public static WaitUtility Instance
        {
            get
            {
                if (_Instance == null)
                {
                    lock (objLock)
                    {
                        if (_Instance == null)
                        {
                            _Instance = new WaitUtility();
                        }
                    }
                }
                return _Instance;
            }
        }

        #endregion

        #region 使用BackgroundWorker来调用等待对话框

        /// <summary>
        /// 等待窗体结束事件
        /// </summary>
        public event WaitDialogEndHandle WaitDialogEnd;

        /// <summary>
        /// 用来异步调用进度对话框
        /// </summary>
        private BackgroundWorker bgWorker;

        /// <summary>
        /// 初始化BackgroundWorker对象
        /// </summary>
        private void InitBgWorker()
        {
            try
            {
                if (bgWorker == null || !bgWorker.IsBusy)
                {
                    bgWorker = new BackgroundWorker();
                    bgWorker.WorkerSupportsCancellation = true;
                    bgWorker.DoWork += bgWorker_DoWork;
                    bgWorker.RunWorkerAsync();
                }
            }
            catch
            {
                bgWorker = null;
                _ShowDialog = false;
                strTip = String.Empty;
            }
        }

        /// <summary>
        /// 销毁BackgroundWorker对象
        /// </summary>
        private void DestroyBgWorker()
        {
            try
            {
                WaitDialogEnd();
            }
            catch
            {
            }
            bgWorker = null;
            _ShowDialog = false;
            strTip = String.Empty;
        }

        /// <summary>
        /// BackgroundWorker对象的后台工作方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void bgWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            WaitDialog dlg = new WaitDialog(strTip);
            this.WaitDialogEnd += dlg.WaitDialogEnd;
            dlg.ShowDialog();
            this.WaitDialogEnd -= dlg.WaitDialogEnd;
            DestroyBgWorker();
        }

        #endregion

        #region 等待对话框操作接口

        private bool _ShowDialog = false;

        /// <summary>
        /// 等待对话框是否显示
        /// </summary>
        public bool ShowDialog
        {
            get
            {
                return _ShowDialog;
            }
        }

        /// <summary>
        /// 显示进度对话框
        /// </summary>
        public void Begin()
        {
            Begin("");
        }

        /// <summary>
        /// 进度对话框提示文本
        /// </summary>
        private string strTip = string.Empty;

        /// <summary>
        /// 显示进度对话框
        /// </summary>
        /// <param name="strTip">进度对话框提示文本</param>
        public void Begin(string strTip)
        {
            this.strTip = strTip;
            _ShowDialog = true;
            InitBgWorker();
        }

        /// <summary>
        /// 关闭进度对话框
        /// </summary>
        public void End()
        {
            DestroyBgWorker();
        }

        #endregion
    }
}

该类是主要的类,提供了Begin和End的对外接口,通过调用Begin来显示进度框,通过调用End来关闭进度框。

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CommonControl.WaitDialog;
using System.Threading;

namespace CommonControl.Test
{
    public partial class Form1 : Form, IMessageFilter
    {
        public bool PreFilterMessage(ref Message msg)
        {
            return WaitUtility.Instance.ShowDialog;
        }

        /// <summary>
        /// 窗体关闭方法
        /// </summary>
        /// <param name="e"></param>
        protected override void OnClosed(EventArgs e)
        {
            ////将消息筛选器从应用程序的消息泵中删除
            Application.RemoveMessageFilter(this);
        }

        public Form1()
        {
            InitializeComponent();
            //将消息筛选器添加到应用程序的消息泵中
            Application.AddMessageFilter(this);
        }

        private void btnRunWait_Click(object sender, EventArgs e)
        {
            WaitUtility.Instance.Begin("等待加载数据!");
            Thread.Sleep(10000);
            WaitUtility.Instance.End();
        }
    }
}

凡是要使用进度框的窗体尽量要实现IMessageFilter接口,并时进度框显示时IMessageFilter.PreFilterMessage方法返回true,这样就可以阻断窗体对windows消息的响应,但同时要将窗体注册到消息泵中,并在窗体关闭时从消息泵中删除窗体,具体代码如上。

如上这些就完成了进度对话框的功能。主要难点有:1. 使用Backgroundworker组件来方便地实现进度对话框的调用和关闭;2. 使用IMessageFilter接口来实现消息过滤,以实现模态对话框的方式,同时不影响后台操作。

时间: 2024-10-27 01:41:39

等待对话框实现的相关文章

主程序,然后才能运行等待对话框响应问题

在项目开发.经常使用对话框,Android该对话框是异步,后再继续运行. 以下以使用AlterDialog对话框返回true或者false之后,主程序再继续运行为例讲述怎样实现主程序等待对话框响应后再顺序运行的方法. 思考一: 首先考虑到声明一个final keyword的布尔型的局部变量,然后在对话框的"确认"和"取消"button的点击事件中对布尔型变量进行赋值.然后再运行主程序. 问题一:在代码的过程对布尔型变量进行赋值的时候提示错误. 错误例如以下:The 

Qt下等待对话框的设计

在Qt程序经常长时间操作时采用一个等待对话框来提示用户正在操作. Qt有标准的QProcessDialog 能部分实现这个功能,但是缺点是要计算进度,二是用户可以中途取消.所以一般我们采用自定义对话框实现这个功能. 常见实现机制 开源项目 QtWaitingSpinner,具体可以下载代码一试,它是自己用代码描绘出进度条动态来了,因此可以调整出不同大小的环形等待标志 https://github.com/snowwlex/QtWaitingSpinner 但是他不是一个独立对话框,因此我们更多使

主程序等待对话框响应后再顺序执行问题

在项目开发中,经常会用到对话框,Android的对话框都是异步进行的,但是有时候需要实现主程序等待对话框响应后再继续执行.下面以使用AlterDialog对话框返回true或者false之后,主程序再继续运行为例讲述如何实现主程序等待对话框响应后再顺序执行的方法. 思考一: 首先考虑到声明一个final 关键字的布尔型的局部变量,然后在对话框的"确认"和"取消"按钮的点击事件中对布尔型变量进行赋值,然后再执行主程序. 问题一:在代码的过程对布尔型变量进行赋值的时候提

4种等待对话框

Qt之等待提示框(QPropertyAnimation) Qt之QProgressIndicator(等待提示框) Qt之等待提示框(QMovie) Qt之等待提示框(QPropertyAnimation)

Robotium API -- 等待执行的方法sleep、waitFor

测试中经常出现明明有控件或者文本,但是由于界面没有载入完成或者其他原因导致assert判断的结果失败.或者两次执行,一次成功,一次失败的情况.所以需要加入这些等待某些控件或者文本载入的方法,以加强程序执行的健壮性. sleep是固定长度时间的等待,waitFor则是等待某个控件或者文本载入后再进行下一步操作. 故两者都能用的情况下,推荐waitFor sleep,固定时间的等待 void sleep(int time) 让测试停止若干时间以便进行下一步操作 参数: time-停止的时间,单位是毫

三、ExtJS之对话框控件

Extjs 在实现消息框的时候,完全摈弃了传统的风格,不再弹出新的对话框,而是在当前页面跳出一个层,并将原页面完整覆盖.原来,只是一种模拟.在 Ext 中,定义了一个类MessageBox,该类还有一个更精简的名字Msg,所有消息框都定义在该类中. 建立dialogs.js文件. 提示框(Alert) 提示框的语法:Ext.MessageBox. alert ( String title, String msg, Function fn, Object scope ); 参数定义如下: titl

[转载]ExtJs4 笔记(6) Ext.MessageBox 消息对话框

作者:李盼(Lipan) 出处:[Lipan] (http://www.cnblogs.com/lipan/)版权声明:本文的版权归作者与博客园共有.转载时须注明本文的详细链接,否则作者将保留追究其法律责任. 本篇演示消息对话框的用法,ExtJs封装了可能用到的各类消息框,并支持自定义的配置. 如下是用到的html: [html] <h1>各种消息框</h1> <div id="div1" class="content"> <

安卓ProgressDialog.show(),无法显示等待框

先给大家把我的解决代码贴出来: package com.park; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Objects; import java.util.Timer; import java.util.TimerTas

Android Volley解析(一)之GET、POST请求篇

一. Volley 的地位 自2013年Google I/O 大会上,Google 推出 Volley 之后,一直到至今,由于其使用简单.代码轻量.通信速度快.并发量大等特点,倍受开发者们的青睐. 先看两张图,让图片告诉我们 Volley 的用处: 第一张 Volley 的经典图 通过上图,我们可以发现 Volley适合网络通信频繁操作,并能同时实现多个网络通信. 第二张图 我们在以前在 ListView 的 item 中如果有网络请求,一般都是通过Task 异步任务来完成,并在完成之后通知 A