前言:

在前面的系列中,我们虽然完成了其大部分功能,但是,离正真运行,还是有一大段距离

当你F5运行时,在弹出对话框之后,如果你不即时点确定,或者上个WC回来之后,你会发现已经提示出错了

这节开始,我们将对其进行一小步一小步的优化,来避免一些明显容易引发的错误。

感知一下最原始的消息弹出框如下图:

一:传统消息框,容易引发命案

1:原始的消息框,是线程阻塞类型的,很容易引发超时问题

线程阻塞?怎么理解?

简单的说就是,WCF服务端给客户端发送了消息提示之后,一直进入等待状态,直到玩家点了确定,这时才继续做其它事情。

会产生什么问题?

玩家上WC去了?消息没人确认,自然就会超时引发异常了,而且那线程也没法接下去干其它活。

解决方案?

a:传统解决方案[加上倒计时,还是线程阻塞类型]

当初我只是想在这传统的消息框上加上倒计时自动确认,这样可以少一点避免超时情况。
于是搜了一些资料,发现要用winapi来处理,这个这个....大才小用了吧。

b:更优的解决方案

无意中发现Silverlight的ChildWindow,正好解决了这一问题。
因为 ChildWindow使用异步方式,非线程阻塞,消息一弹之后线程就回家去了。
而且用Sivlerlight内置的定时器DispatcherTimer,非常容易实现倒计时。

二:实现自定义非线程阻塞倒计时对话框,纯种Sivlerlight

1:看看纯种的长成什么样

新建项目-》Silverlight 子窗口 -》起名叫MsgBox-》找另一个界面调用一下。
比如在登陆页面测试一下:MsgBox box=new MsgBox();box.Show();

结果所见如图:

说明:

1:有背景灰色层,界面原生的还传统消息框好看多了。
2:重点提示:当初刚试的时候是直接运行MsgBox,然后在其构造函数中调用Show(),结果是出不来的。

2:改造-界面小小改动

我们将原来的xaml改造成如下:

<controls:ChildWindow x:Class="ChessProject.MsgBox" ...省略一点...  Width="290" Height="141"  Title="系统消息">
    <Grid x:Name="LayoutRoot" Margin="2" Height="97" Width="270">
        <Button Visibility="Collapsed" x:Name="CancelButton" Content="取消" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,62,93,12" />
        <Button x:Name="OKButton" Content="确定" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,62,10,12" />
        <TextBlock Height="41" TextWrapping="Wrap" HorizontalAlignment="Left" Margin="15,15,0,0" Name="tbMsg" Text="请按确定按钮确定" VerticalAlignment="Top" Width="224" />
    </Grid>
</controls:ChildWindow>

界面效果如图,和上图差不多[这里把取消放在前面,只是为了不显示取消时,确定还保留在原位好看点]:

3:改造,在标题加入倒计时

a:加入计时器并初始化

       DispatcherTimer timer;//定时器
        public MsgBox()
        {
            InitializeComponent();
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += new EventHandler(timer_Tick);
        }

b:新加show方法并实现倒计时

       int defaultTime = 3;//默认N秒
        string userTitle;
       DispatcherTimer timer;//定时器
        public MsgBox()
        {
            //...省略...
        }
        void timer_Tick(object sender, EventArgs e)
        {
            Title = string.Format(userTitle + " [倒计时自动确定:{0}秒]", defaultTime);
            defaultTime--;
            if (defaultTime == 0)
            {
                ResetTimer();
            }
        }
        void ResetTimer()
        {
            timer.Stop();
            defaultTime = 3;
        }
        public void Show(string msg, string title)
        {
            tbMsg.Text = msg;
            userTitle = title;
            Show();
            timer.Start();
        }

c:再调用一下看结果

MsgBox box = new MsgBox();
box.Show("http://cyq1162.cnblogs.com","路过秋天");

如图:

4:扩展show函数:加入回调/倒计时时间/按钮类型/默认确认类型

首先:这个子窗口是异步的,所以,在点击完确定时,需要增加多一个回调函数;
接着:默认3秒,很明显情况不同,时间也要稍为增加变动一下;
然后:有时候按钮只是确定,有时候就是取消+确定;
最后:倒计时时间到了,默认执行确定,还是执行取消。

于是,要实现了:

a:如何实现回调?

默认子窗口就有Closed事件,我们用它的事件,在点击确定或取消时,执行Close()方法

        public MsgBox()
        {
            InitializeComponent();
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += new EventHandler(timer_Tick);
            this.Closed += new EventHandler(MsgBox_Closed);
        }
        void MsgBox_Closed(object sender, EventArgs e)
        {
            //待实现
         }
        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
            Close();//调用一下关闭
        }

private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
            Close();//调用一下关闭
        }

问题?我们难道对所有的确定都执行相同的代码?

首先说:异步不能像同步那样写if(show(xxx,xxx)){方法}
于是说:这是个很严重的问题,因为不同的确定,我们执行的事件肯定是不同的。

解决问题?匿名委托出手了!!!

匿名委托:[Action<T1,T2,T3...N个重载>],这是个很好用的东东,可以传进方法名称,在执行后调用不同的方法。

匿名委托实现:

Action<bool> callBackEvent;//全局定义

void MsgBox_Closed(object sender, EventArgs e)
{
    if (callBackEvent != null)
    {
        callBackEvent(DialogResult.Value);
    }
}

那委托是如何传入的?Show方法增加扩展参数传入。

b:这里贴出完整代码,一并实现:倒计时时间/按钮类型/默认确认类型

完整的MsgBox代码

    public partial class MsgBox : ChildWindow
    {
        int defaultTime = 3;//默认N秒
        string userTitle;
        DispatcherTimer timer;//定时器
        Action<bool> callBackEvent;
        bool autoOKConfirm = true;
        public MsgBox()
        {
            InitializeComponent();
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(1);
            timer.Tick += new EventHandler(timer_Tick);
            this.Closed += new EventHandler(MsgBox_Closed);
        }
        void MsgBox_Closed(object sender, EventArgs e)
        {
            //待实现
        }
        void timer_Tick(object sender, EventArgs e)
        {
            Title = string.Format(userTitle + " [倒计时自动确定:{0}秒]", defaultTime);
            defaultTime--;
            if (defaultTime == 0)
            {
                ResetTimer();
                if (autoOKConfirm)
                {
                    OKButton_Click(null, null);
                }
                else
                {
                    CancelButton_Click(null, null);
                }
            }
        }
        void ResetTimer()
        {
            timer.Stop();
            defaultTime = 3;
        }
        public void Show(string msg, string title)
        {
            Show(msg, title, defaultTime, null, true, MessageBoxButton.OK);
        }
        public void Show(string msg, string title, int timeSecond, Action<bool> callBack)
        {
            Show(msg, title, timeSecond, callBack, false, MessageBoxButton.OKCancel);
        }
        public void Show(string msg, string title, int timeSecond, Action<bool> callBack, bool autoOK, MessageBoxButton button)
        {
            tbMsg.Text = msg;
            userTitle = title;
            if (button == MessageBoxButton.OK)
            {
                OKButton.Content = "确定";
                CancelButton.Visibility = System.Windows.Visibility.Collapsed;
            }
            else
            {
                CancelButton.Visibility = System.Windows.Visibility.Visible;
                OKButton.Content = "同意";
                CancelButton.Content = "拒绝";
            }
            defaultTime = timeSecond;
            autoOKConfirm = autoOK;
            callBackEvent = callBack;
            Show();
            timer.Start();
        }
        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }
    }

三:接下来便是苦力活了,把原来用到传统对框的提示,通通改过来。

这个改的点有点多,留到下节MsgBox使用时细细说了。

最后上一实际应用中的图:

转载于:https://www.cnblogs.com/cyq1162/archive/2010/10/27/1861281.html

Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)相关推荐

  1. Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)...

    前言: 近期在忙点"秋色园"的事情,所以网络象棋这一块文章就写的相对慢,而且刚好接上篇:Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)  之后, ...

  2. Silverlight+WCF 实战-网络象棋最终篇之对战视频-下篇[客户端发送与服务端中转](六)...

    本篇继上一篇:Silverlight+WCF 实战-网络象棋最终篇之对战视频-上篇[客户端开启视频/注册编号/接收视频](五)  一:对战视频 简单原理 略,内容见上篇. 二:对战视频 步骤解析: 略 ...

  3. Silverlight+WCF 实战-网络象棋最终篇之解决重复的消息提示(八)

    前言: 最近有网友经常会问,在跟着做象棋对战的通讯中,在重复退出进入的时候,消息会重复出现,本节就这问题进行解说与优化. 一:分析问题产生的原因? 1:首先看App.xaml,里面定义了一个全局客户端 ...

  4. Silverlight+WCF 新手实例 象棋 主界面-事件区-求和认输(三十二)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 事隔几篇,我们又回到事件区,继续其它两个按钮事件,来张图吧: 在Silverlight+WCF 新手实例 象棋 主界面-事件区- ...

  5. Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放-结局(四十)

    在线演示地址: Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界面-棋谱-回放(三十九)中,我们实现了用户的棋谱回放,在文章的下面,我们 ...

  6. Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)

    2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 在Silverlight+WCF 新手实例 象棋 主界 ...

  7. Silverlight+WCF 新手实例 象棋 主界面-实时聊天区(二十五)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三) 本节连着Silverlight+WC ...

  8. Silverlight+WCF 新手实例 象棋 该谁下棋-B下A停(三十)

    2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 上上一节,就是二十八节:Silverlight+WCF ...

  9. Silverlight+WCF 新手实例 象棋 主界面-事件区-返回退出(三十三)

    在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示 还是那张图: 本节实现返回大厅和退出系统: 一:返回大厅,其实很简单的说,就是转向房间列表了. 可是,转向前也有很多事情要处理的 ...

最新文章

  1. Facebook AI新研究:可解释神经元或许会阻碍DNN的学习
  2. 【解决方案】npm安装vue超时(ERR! errno ETIMEDOUT)
  3. CUDA和cuDNN到底是啥关系?(cuDNN是基于CUDA的深度学习GPU加速库)
  4. appium连接模拟器时屏幕倒转
  5. vue --- vue中的几个钩子属性
  6. Ubuntu中输入输出重定向及管道技术简述
  7. 解决PendingIntent传递参数为空的问题
  8. extjs 在textfield后面加一个button_用python 做一个简单的MP3
  9. 春运期间长江海事局开辟四类运输“绿色通道”
  10. 用批处理读取特定注册表项的路径值
  11. 手把手搭建一个完整的javaweb项目(适合新手)
  12. 七年切图仔如何面试大厂web前端?(沟通软技能总结) | 掘金技术征文
  13. Python爬虫-字体反爬-猫眼国内票房榜
  14. 苹果8p电池多少毫安的_买得起手机未必用得起售后:苹果iPhone12修一下多少钱?|iphone12|手机|电池|iphone...
  15. php压缩文件下载后损坏,php下载压缩文件
  16. java保姆级教程—— 1.什么是游戏
  17. 32位程序和64位程序
  18. SMTP, POP3, IMAP,Exchange ActiveSync区别
  19. 深度学习基础:深入理解Squeeze-and-Excitation (SE)网络
  20. AJAX框架眼镜店活动,眼镜店节日促销H5的活动方案有哪些?快来看看吧!

热门文章

  1. Redis 的主从复制太强大了!
  2. 【Scratch】青少年蓝桥杯_每日一题_7.01_正五边形组成的美丽春花
  3. mysql 打印_故障分析 | MySQL:5.6大事务show engine innodb status故障一例
  4. 成功解决cv2.error: OpenCV(4.1.2) C:\projects\opencv-python\opencv\modules\imgproc\src\color.cpp:182: err
  5. Dataset:Big Mart Sales数据集的简介、下载、案例应用之详细攻略
  6. 成功解决极其刁钻bug之TypeError: ‘<=‘ not supported between instances of ‘list‘ and ‘int‘
  7. 成功解决numpy.ndarray格式类型转数据为list格式数据带有中括号(一行代码搞定!)
  8. DL之模型调参:深度学习算法模型优化参数之对深度学习模型的超参数采用网格搜索进行模型调优(建议收藏)
  9. 成功解决 AttributeError: module 'tensorflow' has no attribute 'sub'
  10. Ubuntu16.04 安装R与RStudio