对delegate进行扩展 打造通用的"计时完成"方法 z
让用户尽量少打字
每次让用户输入这么多信息的确很糟糕, 可以改进一下设计: 服务器IP和用户名可以存放在配置文件里面, 初始化的时候默认加载到相应的文本框中; 从安全角度考虑, 密码必须经过用户手动输入; 而数据库名字则没必要让用户输入, 有了服务器IP、用户名、密码后可以尝试连接SQL Server, 连接SQL Server成功后, 把数据库中所有的数据库名加载到ComboBox让用户选择连接哪个数据库.

密码不正确

密码正确
如何实现
在后台代码中定义一个计时器, 设置它的Interval为1000毫秒, 用户输入密码时让定时器重新计时, 也就是说用户输入密码后, 如果在1秒钟内用户没有继续输入密码, 则会触发计时器的Elapsed事件, 这时程序尝试能不能连上SQL Server.
| 1 2 3 4 5 6 7 8 9 10 11 | //用户停止输入密码1秒后自动尝试连接privateSystem.Timers.Timer m_timer=newSystem.Timers.Timer(1000);        privatevoidtxtPassword_PasswordChanged(objectsender, RoutedEventArgs e){    m_timer.Stop();    m_timer.Start();    //清空数据库的选择列表    cbbDatabase.Items.Clear();} | 
在计时器的Elapsed事件函数中, 程序尝试连接SQL Server, 但是如下写法会出现问题.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | privatevoidtimer_Elapsed(objectsender, ElapsedEventArgs e){    Dispatcher.BeginInvoke((Action)delegate()    {        varconStr = String.Format("Data Source={0};Integrated Security=False;User ID={1};Password={2};", txtServer.Text, txtUser.Text, txtPassword.Password);        using(varcon = newSqlConnection(conStr))        {            try            {                con.Open();            }            catch            {                //TODO: 提示连接数据库失败                return;            }            //TODO:提示连接数据库成功            varsql = "select name from sys.databases";            varcmd = newSqlCommand(sql, con);            IAsyncResult asyncResult = cmd.BeginExecuteReader();            SqlDataReader reader = cmd.EndExecuteReader(asyncResult);            if(!reader.HasRows)            {                //TODO: 提示SQL Server中不存在数据库                return;            }            //TODO: 在这里释放Timer            while(reader.Read())            {                cbbDatabase.Items.Add(reader[0].ToString());            }        }    });} | 
如果数据库的IP是错误的, con.Open()则要花费约30秒左右才会抛出异常, 这段时间UI线程会一直卡死, 经过测试, 30秒后才抛异常与数据库连接字符串的Connect Timeout属性没有关系.
可以写一个SqlConnection的扩展方法, 在这个方法里面用一个码表对执行con.Open()的时间计时, 用一个bool型变量标识有没有成功的con.Open(), 如果在规定的时间内没有成功连上SQL Server则抛出一个异常.
扩展SqlConnection
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | publicstaticclassSqlExtension{    publicstaticvoidTryOpen(thisSqlConnection connection, intmillisecondTimeout)    {        Stopwatch sw = newStopwatch();        boolsucceed = false;        Thread t = newThread(() =>            {                try                {                    sw.Start();                    connection.Open();                    //打开连接后设置succeed为true                    succeed = true;                }                catch                {                }            });        t.IsBackground = true;        t.Start();        t.Join(millisecondTimeout);        t.Abort();        //如果没有成功, 则抛出一个异常        if(!succeed)            thrownewException();    }} | 
这样在原来的代码中调用con.TryOpen()就可以解决问题.
扩展delegate
其实扩展方法的第一个参数并不是一定要是一个class类, 其实delegate也是可以的, delegate其实在编译之后就是一个类, 如下改写刚刚的SqlConnection扩展方法, 就可以写一个通用的尝试操作的扩展方法.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | publicstaticclassActionExtension{    publicstaticvoidInvoke(thisAction action, intmillisecondTimeout)    {        Stopwatch sw = newStopwatch();        boolsucceed = false;        Thread t = newThread(() =>            {                try                {                    sw.Start();                    action();                    succeed = true;                }                catch                {                }            });        t.IsBackground = true;        t.Start();        t.Join(millisecondTimeout);        if(!succeed)            thrownewException();    }} | 
这样写, 代码则更为通用一些, 以后一些耗时的操作(当然要满足Action的签名)都可以调用这个方法, 在本例中, 可以如下调用:
| 1 | ((Action)con.Open).Invoke(2000); | 
对delegate进行扩展 打造通用的"计时完成"方法 z的更多相关文章
- RBAC打造通用WEB权限
		RBAC不用给用户单个分配权限,只用指向对应的角色就会有对应的权限,而且分配权限和收回权限都很方便 5个关系对应5张表 五张表设计 CREATE TABLE `user` ( `id` ) unsig ... 
- 为RecyclerView打造通用Adapter
		##RecycleView简单介绍 RecyclerView控件和ListView的原理有非常多相似的地方,都是维护少量的View来进行显示大量的数据.只是RecyclerView控件比ListVie ... 
- Android教你怎样一步步打造通用适配器
		前言 在Android开发中ListView是最为经常使用的控件之中的一个,基本每一个应用都会涉及到它,要使用ListView列表展示,就不可避免地涉及到另外一个东西--Adapter,我们都知道,A ... 
- 为RecyclerView打造通用Adapter 让RecyclerView更加好用
		原文出处: 张鸿洋 (Granker,@鸿洋_ ) 一.概述 记得好久以前针对ListView类控件写过一篇打造万能的ListView GridView 适配器,如今RecyclerView异军突起, ... 
- 转载扩展Windows Mobile模拟器存储空间的方法
		扩展Windows Mobile模拟器存储空间的方法 在Windows Mobile应用程序开发的初期,可以使用SDK自带的模拟器来进行调试,这给我们开发人员提供了一种方便的途径.一般的应用程序,占用 ... 
- delphi附带通用控件安装方法:
		附带通用控件安装方法:----------基本安装1.对于单个控件,Componet-->install component..-->PAS或DCU文件-->install;2.对于 ... 
- 通用Mapper的各个方法描述,参考官方
		下面是通用Mapper的各个方法描述,主要还是看官方的描述https://mapperhelper.github.io/all/. 基础接口 Select 接口:SelectMapper<T&g ... 
- 关于visual studio code在win10系统上安装后会报扩展宿主意外终止的解决方法
		我的电脑的地址 C:\Users\Administrator.SC-201810160958\AppData\Local\Programs\Microsoft VS Code\resources\ap ... 
- jQuery通用的全局遍历方法$.each()用法实例
		1.jQuery通用的全局遍历方法$.each()用法 2. test.json文件代码: 3. html代码 4.jQuery代码 <script src="jquery-1.3.1 ... 
随机推荐
- Asp.Net缓存(2)
			缓存页的多个版本 ASP.NET 允许在输出缓存中缓存同一页的多个版本.输出缓存可能会因下列因素而异: 初始请求 (HTTP GET) 中的查询字符串. 回发时传递的控制值(HTTP POST 值). ... 
- 使用load()方法异步请求数据
			使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: load(url,[data],[callback]) 参数url为加载服务器地址,可选项d ... 
- JVM基础学习
			public class TestJVM { // 运行时数据区[方法区.堆.程序计数器.虚拟机栈.本地方法栈] private static int _1M = 1024 * 1024; publi ... 
- Hibernate逍遥游记-第10章 映射继承关系-002继承关系树中的根类对应一个表(discriminator、subclass)
			1. 2. <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate ... 
- REACTOS(193)与汇编编译器(69)的高人
			REACTOS(193)与汇编编译器(69)的高人http://blog.csdn.net/caimouse ReactOS编译成VS工程1: 首先从https://www.reactos.org/w ... 
- JavaScript DOM编程基础精华01(DOM入门,DOM模型和获取页面元素,事件,window对象的方法)
			DOM入门 DOM就是Html页面的模型,将每个标签都做为一个对象,JavaScript通过调用DOM中的属性.方法就可以对网页中的文本框.层等元素进行编程控制.比如通过操作文本框的DOM对象,就可以 ... 
- shell编程基础(5)---循环指令
			while类型的循环 while类型的循环是不定循环的一种,每一次循环都会验证给出的循环条件,判断是否要进行下一次循环.linux中while循环的写法和c语言中很想,但是条件给出的方式有些区别. 首 ... 
- class_create()
			#define class_create(owner, name) \({ \ ... 
- Bug调试
			iPhone开发笔记——Xcode升级后的警告.错误的解决办法(一) http://blog.sina.com.cn/s/blog_58af95150101slit.html iPhone开发笔记—— ... 
- php整理(四): mysql
			PHP学习(四)---PHP与数据库MySql 主要有以下的内容: 1.怎么连接数据库 2.怎么操作数据库 (1)怎么执行sql语言 (2)怎么处理返回的结果集 方法一:面向过程(已经过时,只是了解) ... 
