zoukankan      html  css  js  c++  java
  • Silverlight+WCF 实战网络象棋最终篇之非线程阻塞倒计时窗口(四)

    前言:

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

    当你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(
    nullnull);
                    }
                    
    else
                    {
                        CancelButton_Click(
    nullnull);
                    }
                }
            }
            
    void ResetTimer()
            {
                timer.Stop();
                defaultTime 
    = 3;
            }
            
    public void Show(string msg, string title)
            {
                Show(msg, title, defaultTime, 
    nulltrue, 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使用时细细说了。

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

  • 相关阅读:
    哪种写法更好?<script></script> vs/or <script type=”text/javasript”></script>
    JS 脚本应该放在页面哪个位置 head body foot
    List<T> ForEach break
    嵌套JSON 取出name与value
    C# 改变图片尺寸(压缩),Image Resize
    tornado
    appachebench网站压力测试
    mysql分区分表
    redis的持久化存储,RDB与AOF
    MEMCACHE的内存管理和删除策略
  • 原文地址:https://www.cnblogs.com/cyq1162/p/1861281.html
Copyright © 2011-2022 走看看