让用户尽量少打字

每次让用户输入这么多信息的确很糟糕, 可以改进一下设计: 服务器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秒后自动尝试连接
private System.Timers.Timer m_timer=new System.Timers.Timer(1000);
         
private void txtPassword_PasswordChanged(object sender, 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
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    Dispatcher.BeginInvoke((Action)delegate()
    {
        var conStr = String.Format("Data Source={0};Integrated Security=False;User ID={1};Password={2};", txtServer.Text, txtUser.Text, txtPassword.Password);
        using (var con = new SqlConnection(conStr))
        {
            try
            {
                con.Open();
            }
            catch
            {
                //TODO: 提示连接数据库失败
                return;
            }
            //TODO:提示连接数据库成功
 
            var sql = "select name from sys.databases";
            var cmd = new SqlCommand(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
public static class SqlExtension
{
    public static void TryOpen(this SqlConnection connection, int millisecondTimeout)
    {
        Stopwatch sw = new Stopwatch();
        bool succeed = false;
 
        Thread t = new Thread(() =>
            {
                try
                {
                    sw.Start();
                    connection.Open();
                    //打开连接后设置succeed为true
                    succeed = true;
                }
                catch
                {
                }
            });
        t.IsBackground = true;
        t.Start();
        t.Join(millisecondTimeout);
        t.Abort();
 
        //如果没有成功, 则抛出一个异常
        if (!succeed)
            throw new Exception();
    }
}

这样在原来的代码中调用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
public static class ActionExtension
{
    public static void Invoke(this Action action, int millisecondTimeout)
    {
        Stopwatch sw = new Stopwatch();
        bool succeed = false;
 
        Thread t = new Thread(() =>
            {
                try
                {
                    sw.Start();
                    action();
                    succeed = true;
                }
                catch
                {
                }
            });
        t.IsBackground = true;
        t.Start();
        t.Join(millisecondTimeout);
 
        if (!succeed)
            throw new Exception();
    }
}

这样写, 代码则更为通用一些, 以后一些耗时的操作(当然要满足Action的签名)都可以调用这个方法, 在本例中, 可以如下调用:

1
((Action)con.Open).Invoke(2000);

对delegate进行扩展 打造通用的"计时完成"方法 z的更多相关文章

  1. RBAC打造通用WEB权限

    RBAC不用给用户单个分配权限,只用指向对应的角色就会有对应的权限,而且分配权限和收回权限都很方便 5个关系对应5张表 五张表设计 CREATE TABLE `user` ( `id` ) unsig ...

  2. 为RecyclerView打造通用Adapter

    ##RecycleView简单介绍 RecyclerView控件和ListView的原理有非常多相似的地方,都是维护少量的View来进行显示大量的数据.只是RecyclerView控件比ListVie ...

  3. Android教你怎样一步步打造通用适配器

    前言 在Android开发中ListView是最为经常使用的控件之中的一个,基本每一个应用都会涉及到它,要使用ListView列表展示,就不可避免地涉及到另外一个东西--Adapter,我们都知道,A ...

  4. 为RecyclerView打造通用Adapter 让RecyclerView更加好用

    原文出处: 张鸿洋 (Granker,@鸿洋_ ) 一.概述 记得好久以前针对ListView类控件写过一篇打造万能的ListView GridView 适配器,如今RecyclerView异军突起, ...

  5. 转载扩展Windows Mobile模拟器存储空间的方法

    扩展Windows Mobile模拟器存储空间的方法 在Windows Mobile应用程序开发的初期,可以使用SDK自带的模拟器来进行调试,这给我们开发人员提供了一种方便的途径.一般的应用程序,占用 ...

  6. delphi附带通用控件安装方法:

    附带通用控件安装方法:----------基本安装1.对于单个控件,Componet-->install component..-->PAS或DCU文件-->install;2.对于 ...

  7. 通用Mapper的各个方法描述,参考官方

    下面是通用Mapper的各个方法描述,主要还是看官方的描述https://mapperhelper.github.io/all/. 基础接口 Select 接口:SelectMapper<T&g ...

  8. 关于visual studio code在win10系统上安装后会报扩展宿主意外终止的解决方法

    我的电脑的地址 C:\Users\Administrator.SC-201810160958\AppData\Local\Programs\Microsoft VS Code\resources\ap ...

  9. jQuery通用的全局遍历方法$.each()用法实例

    1.jQuery通用的全局遍历方法$.each()用法 2. test.json文件代码: 3. html代码 4.jQuery代码 <script src="jquery-1.3.1 ...

随机推荐

  1. 编写高性能JavaScript【转】

    英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...

  2. IT 基础设施

    http://www.cnblogs.com/wintersun/p/4355267.html

  3. POJ 4044 Score Sequence

    题目链接 题意 :给你两个序列,进行降序排序,找出连续的公共子序列,将这个子序列输出,然后对个位数升序排序,如果个位数相同就按数的大小排,再输出这个新排好的. 思路 :先排序,再找公共子序列,最后个位 ...

  4. MAC OS JAVA环境变量配置

    在  /etc/profile 中 加上这些 #临时提权 sudo su #输入密码 vi /etc/profile #配置JAVA_HOME,此处路径根据自己的版本填写 JAVA_HOME=&quo ...

  5. Android中自定义Checkbox

    custom_checkbox.xml文件: <?xml version="1.0" encoding="utf-8"?> <selector ...

  6. lintcode 中等题:subsets II 带重复元素的子集

    题目 带重复元素的子集 给定一个可能具有重复数字的列表,返回其所有可能的子集 样例 如果 S = [1,2,2],一个可能的答案为: [ [2], [1], [1,2,2], [2,2], [1,2] ...

  7. leetcode 4 : Median of Two Sorted Arrays 找出两个数组的中位数

    题目: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the ...

  8. EXCEL排序

    题目描述:     Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能.     对每个测试用例,首先输出1行“Case i:”,其中 i 是测试用例的编号(从1开始).随后在 N ...

  9. SpringMVC学习总结(三)——Controller接口详解(1)

    4.12.ParameterizableViewController 参数化视图控制器,不进行功能处理(即静态视图),根据参数的逻辑视图名直接选择需要展示的视图. <bean name=&quo ...

  10. 喵星人教你记 HTTP 状态码

    记忆HTTP状态码是有一些困难的,因为状态码很多且很难记忆.GirlieMac,也就是Tomomi Imura利用她巧妙的构思,PS了一系列的HTTP状态信息.在你看过这些图片之后,你绝对可以记住一些 ...