[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. JSONP跨域请求数据报错 “Unexpected token :”的解决办法

    原文  http://www.cnphp6.com/archives/65409 Jquery使用ajax方法实现jsonp跨域请求数据的时候报错 “Uncaught SyntaxError: Une ...

  2. C# WinForm程序打印条码 Code39码1

    做WinForm程序需要打印条码,为了偷懒不想自己写生成条码的程序在网上下载一个标准的39码的字体,在程序里面换上这个条码字体即可打印条码了. 最重要的一点作为记录: 如果想把“123456789”转 ...

  3. Powerdesigner 16.5 从SQL Server 2012做逆向工程时提示:Unable to list tables问题

    公司深圳团队开发有一套系统在华北区这边推向客户,在一次更新补丁时,由于发生了数据字典的变更,但深圳团队并未给出数据库的更新脚本,只给了新版本的数据库创建脚本,为了保证客户方系统中已有数据不丢失,只能自 ...

  4. C头文件和源文件的连

    (http://blog.163.com/yui_program/blog/static/18415541520115177852896/) 一.源文件如何根据#include来关联头文件 1,系统自 ...

  5. 读书笔记_Effective_C++_条款四十四:将与参数无关的代码抽离template

    标题上说“将与参数无关的代码抽离template”,这里的参数既可以指类型,也可以是非类型,我们先来看看非类型的情况. 假定我们要为矩阵写一个类,这个矩阵的行列元素个数相等,是一个方阵,因而我们可以对 ...

  6. Maven Android使用一

    Maven的坐标包括:groupId.artifactId.version.packaging.classifier. groupId:定义当前maven项目隶属的实际项目: artifactId:定 ...

  7. 【迁移学习】2010-A Survey on Transfer Learning

    资源:http://www.cse.ust.hk/TL/ 简介: 一个例子: 关于照片的情感分析. 源:比如你之前已经搜集了大量N种类型物品的图片进行了大量的人工标记(label),耗费了巨大的人力物 ...

  8. 【转载】solr初体验

    [1]http://cxshun.iteye.com/blog/1039445 由于工作原因,这段时间接触到solr,一个基于lucene的企业级搜索引擎.不怎么了解它的童鞋可以去GOOGLE一下. ...

  9. ArcGIS应用——四种计算图斑面积的方法

    ArcGIS中有多种方法可计算出图斑面积,本文总结了四种方法,是否可堪称史上最全? 1.计算几何 本人认为这是最适合非专业人士的方法,直接利用ArcGIS中的计算几何功能进行计算. a.首先添加一do ...

  10. Arcgis报错: Bad login user Failed to execute (CreateEnterpriseGeodatabase).

    在使用工具Create Enterprise Geodatabase的时候报错Bad login user,开始怀疑为密码错误,然后反复在plsql中尝试发现并没有错误,很疑惑,然后去官网查询: Er ...