[CLK Framework] CLK.Threading.PortableTimer - 跨平台的Timer类别

问题情景

开发应用程式的时候,免不了需要加入一些定时执行的设计,例如说:定时更新画面资料、定时检查资料库内容、定时检查通讯是否断线...等等。而.NET Framework也很贴心的提供三种不同的Timer类别,用来帮助开发人员设计出定时执行的功能模组。

.NET Framework提供的三种Timer类别,可以参考Bill叔的部落格:

但是当功能模组的开发,是以跨平台执行为目标来做设计的时候,因为不是每个平台都支援上列三种Timer,所以连带的在跨平台的专案中,也就不支援参考使用.NET Framework所提供的Timer类别。像是下图中所建立的Portable Class Library专案,就无法参考使用到System.Threading.Timer类别。

遇到这样跨平台的功能模组开发,该如何提供跨平台的定时执行功能呢?

解决方案

处理跨平台的定时执行功能,其实解决方案很简单,只要建立一个跨平台的Timer类别,用来提供定时执行的功能,就可以满足这个设计需求。

模组设计

建立Timer类别最简单的设计,就是开启一条独立的执行绪,透过这个执行绪定时去执行Callback函式,这就完成了Timer类别的功能设计。但是因为.NET Framework中所提供的System.Threading.Thread并不支援跨平台使用。所以执行绪的建立工作,必须改为可以跨平台使用的System.Threading.Tasks.Task来建立执行绪,这样才能符合跨平台的开发需求。

使用跨平台的System.Threading.Tasks.Task类别来建立的执行绪,并且使用这个执行绪来定时执行Callback函式,这就完成了跨平台Timer类别的功能设计。

模组下载

程式码下载:由此进入GitHub后,点选右下角的「Download ZIP」按钮下载。

(开启程式码的时候,建议使用Visual Studio所提供的「大纲->折叠至定义」功能来折叠程式码,以能得到较适合阅读的排版样式。)

物件程式

using CLK.Diagnostics;
using System;
using System.Threading;
using System.Threading.Tasks; namespace CLK.Threading
{
    public sealed class PortableTimer : IDisposable
    {
        // Fields
        private readonly ManualResetEvent _executeThreadEvent = new ManualResetEvent(false);         private readonly Action _callback = null;         private readonly int _interval = 0;         // Constructors
        public PortableTimer(Action callback, int interval)
        {
            #region Contracts             if (callback == null) throw new ArgumentNullException();             #endregion             // Require
            if (interval <= 0) throw new ArgumentException();             // Arguments
            _callback = callback;
            _interval = interval;             // Begin
            Task.Factory.StartNew(this.Execute);
        }         public void Dispose()
        {
            // End
            _executeThreadEvent.Set();
        }         // Methods
        private void Execute()
        {
            while (true)
            {
                // Wait
                if (_executeThreadEvent.WaitOne(_interval) == true)
                {
                    return;
                }                 // Execute
                try
                {
                    // Callback
                    _callback();
                }
                catch (Exception ex)
                {
                    // Fail
                    DebugContext.Current.Fail(string.Format("Action:{0}, State:{1}, Message:{2}", "Callback", "Exception", ex.Message));
                }
            }
        }
    }
}

使用范例

CLK.Threading.Samples.No001 - 在Windows Store App中使用PortableTimer

  • 使用范例

    using System;
    using System.Threading;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls; namespace CLK.Threading.Samples.No001
    {
        public sealed partial class MainPage : Page
        {
            // Fields
            private readonly object _syncRoot = new object();         private readonly SynchronizationContext _syncContext = null;         private PortableTimer _operateTimer = null;         // Constructors
            public MainPage()
            {
                // Base
                this.InitializeComponent();             // SyncContext
                _syncContext = SynchronizationContext.Current;
            }         // Handlers
            private void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer != null) return;                 // Begin
                    _operateTimer = new PortableTimer(this.Timer_Ticked, 500);
                }
            }         private void MainPage_Unloaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer == null) return;                 // End
                    _operateTimer.Dispose();
                    _operateTimer = null;
                }
            }         private void Timer_Ticked()
            {
                System.Threading.SendOrPostCallback methodDelegate = delegate(object state)
                {
                    // Display
                    this.TextBlock001.Text = DateTime.Now.ToString();
                };
                _syncContext.Post(methodDelegate, null);
            }
        }
    }
  • 执行结果

CLK.Threading.Samples.No002 - 在Windows Phone App中使用PortableTimer

  • 使用范例

    using System;
    using System.Windows;
    using Microsoft.P​​hone.Controls;
    using System.Threading; namespace CLK.Threading.Samples.No002
    {
        public partial class MainPage : PhoneApplicationPage
        {
            // Fields
            private readonly object _syncRoot = new object();         private readonly SynchronizationContext _syncContext = null;         private PortableTimer _operateTimer = null;         // Constructors
            public MainPage()
            {
                // Base
                this.InitializeComponent();             // SyncContext
                _syncContext = SynchronizationContext.Current;
            }         // Handlers
            private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer != null) return;                 // Begin
                    _operateTimer = new PortableTimer(this.Timer_Ticked, 500);
                }
            }         private void PhoneApplicationPage_Unloaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer == null) return;                 // End
                    _operateTimer.Dispose();
                    _operateTimer = null;
                }
            }         private void Timer_Ticked()
            {
                System.Threading.SendOrPostCallback methodDelegate = delegate(object state)
                {
                    // Display
                    this.TextBlock001.Text = DateTime.Now.ToString();
                };
                _syncContext.Post(methodDelegate, null);
            }
        }
    }
  • 执行结果

CLK.Threading.Samples.No003 - 在WPF中使用PortableTimer

  • 使用范例

    using System;
    using System.Threading;
    using System.Windows; namespace CLK.Threading.Samples.No003
    {
        public partial class MainWindow : Window
        {
            // Fields
            private readonly object _syncRoot = new object();         private readonly SynchronizationContext _syncContext = null;         private PortableTimer _operateTimer = null;         // Constructors
            public MainWindow()
            {
                // Base
                this.InitializeComponent();             // SyncContext
                _syncContext = SynchronizationContext.Current;
            }         // Handlers
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer != null) return;                 // Begin
                    _operateTimer = new PortableTimer(this.Timer_Ticked, 500);
                }
            }         private void Window_Unloaded(object sender, RoutedEventArgs e)
            {
                lock (_syncRoot)
                {
                    // Require
                    if (_operateTimer == null) return;                 // End
                    _operateTimer.Dispose();
                    _operateTimer = null;
                }
            }         private void Timer_Ticked()
            {
                System.Threading.SendOrPostCallback methodDelegate = delegate(object state)
                {
                    // Display
                    this.TextBlock001.Text = DateTime.Now.ToString();
                };
                _syncContext.Post(methodDelegate, null);
            }
        }
    }
  • 执行结果

[CLK Framework] CLK.Threading.PortableTimer - 跨平台的Timer类别的更多相关文章

  1. [CLK Framework] CLK.Settings - 跨平台的参数存取模块

    [CLK Framework] CLK.Settings - 跨平台的参数存取模块 问题情景 开发功能模块的时候,常常免不了有一些参数(例如ConnectionString),需要存放在Config檔 ...

  2. [Architecture Design] CLK Architecture

    CLK.Prototype.Architecture 最近找数据,看到了博客园在不久之前,办了一个架构分享的活动:.Net项目分层与文件夹结构大全.看完之后觉得获益良多,接着也忍不住手痒,开始整理属于 ...

  3. Forms.Timer、Timers.Timer、Threading.Timer的研究

    .NET Framework里面提供了三种Timer System.Windows.Forms.Timer System.Timers.Timer System.Threading.Timer 一.S ...

  4. Microsoft Win32 to Microsoft .NET Framework API Map

    Microsoft Win32 to Microsoft .NET Framework API Map .NET Development (General) Technical Articles   ...

  5. .net Framework Class Library(FCL)

    from:http://msdn.microsoft.com/en-us/library/ms229335.aspx 我们平时在VS.net里引用的那些类库就是从这里来的 The .NET Frame ...

  6. System.Windows.Forms.Timer与System.Timers.Timer的区别(zz)

    .NET Framework里面提供了三种Timer: System.Windows.Forms.Timer System.Timers.Timer System.Threading.Timer VS ...

  7. 拥抱.NET Core,如何开发一个跨平台类库 (1)

    在此前的文章中详细介绍了使用.NET Core的基本知识,如果还没有看,可以先去了解“拥抱.NET Core,学习.NET Core的基础知识补遗”,以便接下来的阅读. 在本文将介绍如何配置类库项目支 ...

  8. [C#].NET中几种Timer的使用

    这篇博客将梳理一下.NET中4个Timer类,及其用法. 1. System.Threading.Timer public Timer(TimerCallback callback, object s ...

  9. .NET Core与.NET Framework、Mono之间的关系

    随着微软的.NET开源的推进,现在在.NET的实现上有了三个.NET Framework,Mono和.NET Core.经常被问起Mono的稳定性怎么样,后续Mono的前景如何,要回答这个问题就需要搞 ...

随机推荐

  1. [转]Python零碎知识(2):强大的zip

    一.代码引导 首先看这一段代码: 1 >>> name=('jack','beginman','sony','pcky') 2 >>> age=(2001,2003 ...

  2. bash + script

    shell "" 保留$,`,\, 换行含义,‘’保留字面值 $(), ``用于命令替换 算术扩展如 $[1+1] for循环: for Host in host1, host2, ...

  3. MyEclipse自动生成hibernate实体类和配置文件攻略

    步骤1:找到导航栏里面的window--showView然后输入db brower,打开数据库浏览窗口步骤2:在数据库浏览窗口里只有一个Myeclipse自带的数据库,该数据没有用,我们在空白的地方右 ...

  4. 【cs229-Lecture17】离散与维数灾难

    主要内容: 解决MDP问题的算法: 离散化: 模型MDP的同化型: (model/similator) 拟合值迭代算法: Q函数: 近似政策迭代: 笔记转自:http://blog.csdn.net/ ...

  5. Spring中加载ApplicationContext.xml文件的方式

    Spring中加载ApplicationContext.xml文件的方式 原文:http://blog.csdn.net/snowjlz/article/details/8158560 1.利用Cla ...

  6. ECMASCRIPT 6中字符串的新特性

    本文将覆盖在ECMAScript 6 (ES6)中,字符串的新特性. Unicode 码位(code point)转义 Unicode字符码位的长度是21位[2].而JavaScript的字符串,是1 ...

  7. Spring MVC全局异常处理与拦截器校检

    在使用Spring MVC进行开发时,总是要对系统异常和用户的异常行为进行处理,以提供给用户友好的提示,也可以提高系统的安全性. 拦截系统响应错误 首先是拦截系统响应错误,这个可以在web.xml中配 ...

  8. 在Asp.Net MVC中使用ModelBinding构造Array、List、Collection以及Dictionary

    在asp.net mvc中,我们可以在html表单中使用特定的格式传递参数,从而通过model binder构造一些集合类型. 第一种方式 public ActionResult Infancy(Pe ...

  9. springMVC源码分析之拦截器

    一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...

  10. 11.22 点餐APP第一阶段总结

    第一个冲刺结束了,任务也算是完成了. 团队合作不像单独做那样想怎么来就怎么来,各个人都不同的意见,最后方案的需要每个人一致同意通过才能执行. 不过团队合作分配到每个人的任务也相对轻一点,而且遇到问题解 ...