实现等待窗体的几种方式
实现等待窗体的几种方式:
下面说明了五种可以实现等待窗体的方式,其中三种给出了代码。
准备资料
安全访问控件成员
为了保证在创建控件的线程上调用控件成员,用下面的方式封装控件的属性、方法、其他自定义成员的访问。
如: winWordControl.LoadDocument()封装为:
delegate void VoidDelegate();
private void LoadDocument()
{
if (InvokeRequired)
{
Invoke(new VoidDelegate(LoadDocument));
return;
}
this.winWordControl.LoadDocument();
}
下面的代码封装了winWordControl.OpenMode=Opration
private delegate void OpenModeDelegate(Operation op);
private void OpenMode(Operation value)
{
if (InvokeRequired)
{
Invoke(new OpenModeDelegate(OpenMode), new object[] { value });
return;
}
winWordControl.OpenMode = value;
}
这些封装保证了对控件成员的访问在任何线程都是安全的。
例子说明
例子假定有三个窗体:
MainForm:
Preview preview;//Preview 是在此线程创建
Privite void SomeMethod()
{
Thread wordInit = new Thread(new ThreadStart(preview.InitWordDocControl));
wordInit.Start();
}
第二个窗体
PreviewForm:
WinWordControl winWordControl = new WinWordControl();
Private void InitWordDocControl()
{
//执行初始化加载word、实现延迟窗体
//TODO
}
第三个窗体
WaitForm:提示信息
实现方式
InitWordDocControl为了在加载word时不出现假死,必须开启新线程。
由于用到了非托管资源,最简单的方式是把托管资源(WaitForm)放在工作线程,线程结束,窗体会自动销毁,不用自己写清理代码。
第一种:ShowDialog
ShowDialog自动阻塞当前线程,这使它成为最优的解决方式。
Private void InitWordDocControl()
{
Thread thread = new Thread(new ThreadStart(Waiting));
thread.Start();
LoadDocument();
thread.Abort();//销毁线程,自动回收托管资源
}
private void Waiting()
{
//局部变量,在此线程创建,可以直接操作其成员
Wait FormWait = new Wait();
FormWait.StartPosition = FormStartPosition.CenterScreen;
FormWait.ShowDialog(); //线程等待
}
private void LoadDocument()
{
if (InvokeRequired)
{
Invoke(new VoidDelegate(LoadDocument));
return;
}
this.winWordControl.LoadDocument();
}
最简单的解决方式,利用了托管资源的优势和ShowDialog本身的特性。
第二种:Show
如果简单的修改Waiting为:
private void Waiting()
{
Wait FormWait = new Wait();
FormWait.StartPosition = FormStartPosition.CenterScreen;
FormWait.Show(); //窗体立即被销毁
}
窗体肯定会一闪而过,因为FormWait是局部变量,出了方法体就会被回收。
因此要改成下面的形式:
首先把局部变量改为字段,让他在加载类型时分配内存。其次,做如此修改后,创建Wait的线程就变成了创建Preview的线程,这样就不能直接修改此窗体属性,必须用Invoke。
private void Waiting()
{
//下面的调用都是线程安全的,内部都会判断是否是创建线程,不是会调用Invoke
CreateWait();
SetFormStartPosition(FormStartPosition.CenterScreen);
ShowWait();
}
修改:
Private void InitWordDocControl()
{
Thread thread = new Thread(new ThreadStart(Waiting));
thread.Start();
thread.Join();//阻塞调用线程,让其先执行完show
LoadDocument();
}
修改LoadDocument()
private void LoadDocument()
{
if (InvokeRequired)
{
Invoke(new VoidDelegate(LoadDocument));
return;
}
this.winWordControl.LoadDocument();
CloseWait(); //释放资源,线程自动销毁。注意也要使用线程安全的形式。
}
第三种:异步委托
本质上通过线程池中的线程执行委托方法,仍然是线程问题。但是可以用show和异步委托结合,简单的实现等待。可以看出代码比上面实现简单许多。
首先这次把加载word放到新线程中,而WaitForm在原线程。
修改:
Private void InitWordDocControl()
{
Waiting();
MethodInvoker mi = new MethodInvoker(LoadDocument);
mi.BeginInvoke(AsyncCallClose,null);//执行完委托方法,执行AsyncCallClose来关闭等待窗体。
}
private void AsyncCallClose(IAsyncResult ar)
{
FormWait.Close();
}
MethodInvoker,只是系统定义的委托,提供些许便利,更好的方式是自己定义如:
delegate void VoidDelegate();VoidDelegate 和MethodInvoker是等价的。
在这种实现中发现了下面的问题:控件成员可以不在创建控件的线程中使用!!如FormWait.Close();调用此语句的是线程池中的线程,而FormWait是在另外的线程中创建。不知道是什么原因??按照必须在创建控件线程调用成员,则会抛异常。按照许多资料,这种情况也是非法调用,但在此却没有问题?!
第四种:信号量
以前没有用过线程,遇到这个问题,首先想到的是信号量来控制线程通信。可以参考后面的资料或者我以前的文章:
http://www.cnblogs.com/bluewater/archive/2006/08/14/476720.html
第五种:Timer
本质也是线程,有同学说,他一直在VB中用Timer来模拟线程来控制时间片。应该也能实现等待窗体。
在此使用线程,主要是为了有好的用户体验,避免假死。
第一次使用线程,查了许多资料,但仍然有个问题没有解决,再写一遍,希望有人指点原因。
在这种实现中发现了下面的问题:控件成员可以不在创建控件的线程中使用!!如FormWait.Close();调用此语句的是线程池中的线程,而FormWait是在另外的线程中创建。不知道是什么原因??按照必须在创建控件线程调用成员,则会抛异常。按照许多资料,这种情况也是非法调用,但在此却没有问题?!
资料:
一系列关于线程的入门文章,非常好
http://www.yoda.arachsys.com/csharp/threads/parameters.shtml
关于UI
http://msdn.microsoft.com/msdnmag/issues/03/02/Multithreading/
关于Timer
http://msdn.microsoft.com/msdnmag/issues/04/02/TimersinNET/default.aspx
实现等待窗体的几种方式相关推荐
- 一起谈.NET技术,C#创建不规则窗体的几种方式
现在,C#创建不规则窗体不是一件难事,下面总结一下: 一.自定义窗体,一般为规则的图形,如圆.椭圆等. 做法:重写Form1_Paint事件(Form1是窗体的名字),最简单的一种情况如下 ...
- Task_等待任务完成几种方式
1.0 ContinueWith 在ContinueWith会得到上个任务的结果并且可以用IsFaulted判断上个任务是否出现异常! var t = Task.Run(() => { thro ...
- 第四节:Task的启动的四种方式以及Task、TaskFactory的线程等待和线程延续的解决方案
一. 背景 揭秘: 在前面的章节介绍过,Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然也可以基本业务需要的多线程场景,但它们在多个线程的等待处理方面 ...
- 两种方式实现登录跳转新窗体
两种方式实现登录跳转新窗体 直接隐藏登录窗体 显示主界面 //验证是否有此用户 int? flag = studentService.StudentLogin(userNameText.Text.Tr ...
- VC++等待光标的两种实现方式
VC++等待光标的两种实现方式 有时候在做烦琐的工作时,希望鼠标处于忙状态,有两种简单的方法来实现: 1. 采用ApI函数,大多数采用此方法: BeginWaitCursor(); .....处理.. ...
- Winform中通过NPOI导出Excel的三种方式(HSSFWorkbook,XSSFWorkbook,SXSSFWorkbook)附代码下载
场景 HSSFworkbook,XSSFworkbook,SXSSFworkbook区别 HSSFWorkbook: 是操作Excel2003以前(包括2003)的版本,扩展名是.xls:导出exce ...
- 返回ajax有几种方式,java ajax返回 Json 的 几种方式
方式 1. : 自写代码转 Json 需要 HttpHttpServletRequest request HttpServletResponse response 后台 : @RequestMap ...
- Qt开发应用程序的两种方式
目录 案例:计算圆面积(两种方式实现) 方式一:设计器 Qt Designer实现 (20201015) 方案A:触发按钮事件(_clicked()) 方案B:触发输入编辑框事件(_textCha ...
- ASP.NET页面之间传递值的几种方式
页面传值是学习asp.net初期都会面临的一个问题,总的来说有页面传值.存储对象传值.ajax.类.model.表单等.但是一般来说,常用的较简单有QueryString,Session,Cookie ...
最新文章
- RDKit | 分子坐标的测量和绘图
- 设置UIButton上面是image,下面是title
- 【LeetCode】0046.全排列 (递归详解)
- odoo10 ORM操作
- 图片压缩上传Thumbnailator 插件
- 七桥问题c语言程序数据结构,数据结构与算法学习——图论
- 【LeetCode】剑指 Offer 60. n个骰子的点数
- 腾讯员工每年写3万行代码;马斯克承认利用摄像头监视车主;Chrome 89上线实时字幕 | 极客头条...
- js获取image中src属性的方法语句
- 啊哈算法(pdf免积分下载)
- shell脚本日常机房巡检
- mac book air 外接USB无线网卡TP-LINK TL WN821N
- Navicat Premium15 注册出现No all pattern found! file already patched?
- 机器学习-有监督学习-分类算法:SVM/支持向量机【SVM:高维空间里用于二分类的超平面;支持向量:超平面附近隔离带边界上的样本】【求参数(ω,b)使超平面y(x)=Φ(x)·ω+b能最优分隔两集合】
- 如何通过 onstat 命令监控GBase8s数据库
- WP7 个人股票软件 GilStock v1.0 正式版
- Google中国招聘三大标准 实干、内功与人品
- 我是如何获取到全校同学的证件照?
- 谷歌FLAN-T5作者亲讲:5400亿参数,1800个任务,如何实现大语言模型“自我改进”...
- linux系统查看IP地址,不显示IP地址或者只显示127.0.0.1
热门文章
- PHP获取当前时间差8小时的问题
- Photoshop图像处理操作汇总
- 【C++】C++11 STL算法(八):对未初始化内存的操作(Operations on uninitialized memory)、C库(C library)
- linux 测试环境启用jar_Linux下用java -jar运行可执行jar包的方法教程
- 上面一个星星下面一个r_中国第一个王朝不是夏朝?山西出土一个破陶壶,上面俩字揭开谜题...
- 微信小程序进度条样式_微信小程序组件progress进度条解读和分析
- Java学习总结:31(StringBuffer类)
- 怎么看懂c语言程序,求讲解一下这个程序,我看了1个小时都没有看懂,
- 【java】兴唐第十七节课
- Android 活动与活动间数据传递--登录注册页面