[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. eclipse从数据库逆向生成Hibernate实体类

    做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么 ...

  2. C# 128位AES 加密解密 (转)

    /// AES加密 2         /// </summary> 3         /// <param name="inputdata">输入的数据 ...

  3. D3D11中的MSAA

    这两年我的工作都转到了D3D11,目前新出硬件几乎全部支持此标准,加上D3D11接口清晰,概念直观,等到windows7普及,想必未来都是D3D11的天下.最近时间较空,我陆续开始写些基础文章,希望对 ...

  4. android 中targetSdkVersion和与target属性的区别

    AndroidMenifest.xml中targetSdkVersion和project.properties中的target属性的区别      在AndroidMenifest.xml中,常常会有 ...

  5. 手机浏览器JS识别

    识别方法:采用Fiddler 抓包工具 侦测手机http链接,抓取http头 查看 工具:Fiddler 1:Fiddler配置 允许远程设备连接,配置端口为默认8888(确保8888端口没有被其他进 ...

  6. 编写高质量JS代码的68个有效方法(九)

    No.41.将原型视为实现细节 Tips: 对象是接口,原型是实现 避免检查你无法控制的对象的原型结构 避免检查实现在你无法控制的对象内部的属性 我们可以获取对象的属性值和调用其方法,这些操作都不是特 ...

  7. Nopcommerce主要的技术

    Nopcommerce主要用到的技术及特点: 1.Entity Framework 2.ASP.NET mvc 3.IoC容器+依赖注入(Autofac) 4.使用EF中的EntityTypeConf ...

  8. 剑指架构师系列-Struts2构造函数的循环依赖注入

    Struts2可以完成构造函数的循环依赖注入,来看看Struts2的大师们是怎么做到的吧! 首先定义IBlood与BloodImpl类: public interface IBlood { } pub ...

  9. iOS- 微信支付 (服务器调起支付 )以及回调不成功的原因 不看后悔

    写的不错,给留个言哈... 一. 支付准备工作 1. 微信相关准备工作 (1) 向微信官方开通支付功能. 这个不是前端的工作. (2) 导入官方下载的微信支付SDK包. 我用的是微信开放平台下载的SD ...

  10. ActiveMQ学习(三)——MQ的通讯模式

    1) 点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一.一对多.多对多.多对一等多种配置方式,支持树状.网状等多种拓扑结构. 2) 多点广播:MQ适用于不同类型的应用.其中重要的,也是正 ...