• 在Silverlight中的DispatcherTimer的Tick中使用基于事件的异步请求


    需求:在silverlight用户界面上使用计时器定时刷新数据。

    在 Silverlight 中的 DispatcherTimer 的 Tick 事件 中使用异步请求数据时,会出现多次请求的问题,以下是ViewModel的代码,看样子没什么问题:

    using System;
    using System.Net;
    using System.Threading;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    
    namespace AsyncTest.ViewModel
    {
        public class MainPageViewModel : NotificationBase
        {
            private int count;
            public int Count
            {
                get
                {
                    return count;
                }
                set
                {
                    this.count = value;
                    base.OnPropertyChanged("Count");
                }
            }
    
            protected WcfService.Service1Client client = null;
            private DispatcherTimer timer = null;
            protected int Interval = 1;
    
            public MainPageViewModel()
            {
                client = new WcfService.Service1Client();
                timer = new DispatcherTimer();
                timer.Interval = new System.TimeSpan(0, 0, Interval);
                timer.Tick += timer_Tick;
                timer.Start();
            }
            private void timer_Tick(object sender, EventArgs ee)
            {
                client.GetDataAsync();
                client.GetDataCompleted += ((s, e) => {
                    this.Count++;
                });
            }
        }
    }

    然而,结果并不是我们预期的那样,每次请求成功后,Count会以这样的数列进行累加:1 3 6 10 15 21 。

    经调试三天,排除在View层对ViewMode进行了多次初始化使Timer多次创建实例的可能,其他各种情况都排除后,最终把问题锁定在Tick的方法体。

    后来又经过再三调试,终于知道特么的问题在哪了,卧槽我艹,允许我爆一句粗口,搞了两三天,妈蛋,才发现问题这么简单,仔细观察代码,可以看出这是基于事件的异步编程模型

    问题:在Tick的方法里,client.GetDataCompleted+=((s,e)=>{//do something}); ,那么每次到了Tick执行周期的时候都会"+=" 一次事件,所以给了我们多次请求的错觉,实际是请求了一次,只是多次执行了Completed事件而已。

    这就是为什么Count的结果不是我们预期的 1 2 3 4 5 6 ... ,修改的代码如下:

        private void timer_Tick(object sender, EventArgs ee)
            {
                client.GetDataAsync();
                client.GetDataCompleted += client_GetDataCompleted;
            }
    
            void client_GetDataCompleted(object sender, WcfService.GetDataCompletedEventArgs e)
            {
                //移除该事件,防止下次Tick事件执行时再次注册
                client.GetDataCompleted -= client_GetDataCompleted;
                this.Count++;
            }
     

    将Completed的事件单独提出来,在每次进入到Completed后,使用 "-=" 取消注册该事件,再次进入到Tick的时候,重新请求,重新绑定就OK了,也可以直接在ViewModel的构造函数里绑定Completed事件,每次Tick里只请求client.GetDataAsync(),不需要在进行+=client_GetDataCompleted ,两种方法皆可。

    注意:实际项目中用到的是client_GetDataCompeleted事件的e.Result,这里是为了方便调试写的一个Demo,使用Count的目的是为了监测Compeleted到底执行了几次。

    心得:每次遇到问题,不要急躁,可以由复杂到简单,若不知问题在哪可使用排除法将问题逐一排除,最后查找到问题所在,仔细分析,不断调试,找到问题根本,得到解决。

    完!

  • 相关阅读:
    「NOTE」支配树
    「SOL」支配 (2021省选A卷)
    「SOL」矩阵游戏 (2021省选A卷)
    「SOL」最差记者2 (LOJ / JOISC2016)
    「SOL」Nondivisible Prefix Sums(AtCoder)
    「SOL」Spaceship(LOJ/USACO)
    「NOTE」可持久化非旋Treap
    「SOL」事情的相似度(LOJ)
    FTP(File Transfer Protocol)——文件传输协议详解
    DHCP(Dynamic Host Configutation Protocol)——动态主机配置协议详解
  • 原文地址:https://www.cnblogs.com/tonge/p/4610201.html
Copyright © 2020-2023  润新知