C# 多线程窗体的创建

  从目前已经在项目中工作将近一个月来的情况来看,凡是费时的操作,基本上都要用到多线程的等待窗体、进度提示窗体等实时显示动态的进度信息。而如果直接在主线程的窗体上实时更新信息,就会造成更新太快或者太慢而出现的进程假死现象。为了缓解这些情况,本文就参考一些文章,把他们的智慧总结于此。希望对大家有所帮助。

一、多线程中创建等待窗体

  在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。

2. heoo多线程之进度条,  2013.

时间: 2024-10-11 09:09:36

C# 多线程窗体的创建的相关文章

Qt多线程学习:创建多线程

[为什么要用多线程?] 传统的图形用户界面应用程序都仅仅有一个运行线程,而且一次仅仅运行一个操作.假设用户从用户界面中调用一个比較耗时的操作,当该操作正在运行时,用户界面一般会冻结而不再响应.这个问题能够用事件处理和多线程来解决. [Linux有线程的概念吗?] 传统的UNIX系统也支持线程的概念,但一个进程里仅仅同意有一个线程,这样多线程就是多进程.Linux下的Posix线程(pthreads)是一种轻量级的进程的移植性实现,线程的调度由内核完毕,每一个线程都有自己的编号.假设使用线程,整体

在窗体上创建自己的光标并输入文字

我们知道在文本框等可以接收输入的组件中,我们可以看到闪烁的光标,并可以输入文字,如果我们在,比如窗体上时,因为不支持输入,也无法显示闪烁的光标,那我们 有办法做自己的输入吗?当然可以,下面我们演示在Form上来输入文字. 用到的API函数如下 GetTextMetrics:获取程序当前的字体信息,存放到TEXTMETRIC结构中 CreateCaret:为系统插入标记创建一个新的形状,并且将插入标记的属主关系指定给特定的窗口.插入标记的形状.可以是线.块或位图 ShowCaret:显示光标 Se

Java多线程:如何创建线程?

在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识,然后再阐述如何创建线程以及如何创建进程.下面是本文的目录大纲: 一.Java中关于应用程序和进程相关的概念 二.Java中如何创建线程 三.Java中如何创建进程 若有不正之处,请多多谅解并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/391351

delphi 窗体的创建和释放

Delphi中的窗体分为模式窗体和无模式窗体.二者的区别在于,用户可以在无模式窗体和其他窗体之间切换.这样,用户就可以同时工作于一个应用程序的几个部分.Delphi中窗体的初始化有两种情况,动态创建,和自动创建.通过show显示一个无模式窗体,ShowModal显示一个模式窗体.窗体有创建对应的也要考虑释放问题.当关闭一个窗体时,窗体并没有真正从内存中释放掉,它仍然存在于内存中,除非关闭了主窗体.因为模式窗体于无模式窗体的不同,所以二者的释放处理也有不同. 模式窗体的创建与释放 因为模式窗体可以

Java语言基础-多线程-①线程的创建和启动

简单阐释进程和线程 对于进程最直观的感受应该就是“windows任务管理器”中的进程管理: (计算机原理课上的记忆已经快要模糊了,简单理解一下):一个进程就是一个“执行中的程序”,是程序在计算机上的一次运行活动.程序要运行,系统就在内存中为该程序分配一块独立的内存空间,载入程序代码和资源进行执行.程序运行期间该内存空间不能被其他进程直接访问.系统以进程为基本单位进行系统资源的调度和分配.何为线程?线程是进程内一次具体的执行任务.程序的执行具体是通过线程来完成的,所以一个进程中至少有一个线程.回忆

Java多线程系列-线程创建

1.怎样创建多线程? Java从语言级别实现多线程,因此实现一个多线程程序很easy.有两种方法能够实现多线程,即继承Thread类和实现Runnable接口.由于Java不支持多继承的原因,建议尽可能通过实现Runnable接口实现多线程. 使用Runnable接口实现多线程有例如以下长处: 1.能够避免由于Java的单继承特性而带来的局限. 2.增强程序的健壮性.代码能够被多个线程共享.代码与数据是独立的: 3.适合多个同样程序代码的线程区处理同一资源的情况. 两者之间的不同: *Threa

单击事件的处理方式及注册窗体的创建之(三)注册窗体的创建流程

开发步骤: ? 在res下drawable下创建一个新窗体的布局xml文件 ? 在Java下org.mydiary.socrates.activity下创建一个对应的界面java类,该类必须继承android.app.AppcompatActivity父类,同时实现一个Oncreate()方法,并设置该窗体所绑定的布局xml文件 public class Register_Activity extends AppCompatActivity { @Override protected void

深入VCL源码研究DELPHI窗体的创建和关闭

一.窗体的建立 在DELPHI中,我们通常使用Application.CreateForm(TForm2, Form2)和TForm.create来创建窗体,我们几乎无法区别这两种方法差异,更何况,我们更多的时候都是在使用TForm.create来生成子窗体. 不过,仔细观察VCL源码,你会发现,其实两者区别很大. procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference); var Insta

Java基础加强之多线程篇(线程创建与终止、互斥、通信、本地变量)

线程创建与终止 线程创建 Thread类与Runnable接口的关系 public interface Runnable { public abstract void run(); } public class Thread implements Runnable { /* What will be run. */ private Runnable target; ...... /** * Causes this thread to begin execution; the Java Virtu