[CLK Framework] CLK.Threading.PortableTimer - 跨平台的Timer类别
[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.Phone.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类别的更多相关文章
- [CLK Framework] CLK.Settings - 跨平台的参数存取模块
[CLK Framework] CLK.Settings - 跨平台的参数存取模块 问题情景 开发功能模块的时候,常常免不了有一些参数(例如ConnectionString),需要存放在Config檔 ...
- [Architecture Design] CLK Architecture
CLK.Prototype.Architecture 最近找数据,看到了博客园在不久之前,办了一个架构分享的活动:.Net项目分层与文件夹结构大全.看完之后觉得获益良多,接着也忍不住手痒,开始整理属于 ...
- Forms.Timer、Timers.Timer、Threading.Timer的研究
.NET Framework里面提供了三种Timer System.Windows.Forms.Timer System.Timers.Timer System.Threading.Timer 一.S ...
- Microsoft Win32 to Microsoft .NET Framework API Map
Microsoft Win32 to Microsoft .NET Framework API Map .NET Development (General) Technical Articles ...
- .net Framework Class Library(FCL)
from:http://msdn.microsoft.com/en-us/library/ms229335.aspx 我们平时在VS.net里引用的那些类库就是从这里来的 The .NET Frame ...
- System.Windows.Forms.Timer与System.Timers.Timer的区别(zz)
.NET Framework里面提供了三种Timer: System.Windows.Forms.Timer System.Timers.Timer System.Threading.Timer VS ...
- 拥抱.NET Core,如何开发一个跨平台类库 (1)
在此前的文章中详细介绍了使用.NET Core的基本知识,如果还没有看,可以先去了解“拥抱.NET Core,学习.NET Core的基础知识补遗”,以便接下来的阅读. 在本文将介绍如何配置类库项目支 ...
- [C#].NET中几种Timer的使用
这篇博客将梳理一下.NET中4个Timer类,及其用法. 1. System.Threading.Timer public Timer(TimerCallback callback, object s ...
- .NET Core与.NET Framework、Mono之间的关系
随着微软的.NET开源的推进,现在在.NET的实现上有了三个.NET Framework,Mono和.NET Core.经常被问起Mono的稳定性怎么样,后续Mono的前景如何,要回答这个问题就需要搞 ...
随机推荐
- eclipse从数据库逆向生成Hibernate实体类
做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么 ...
- C# 128位AES 加密解密 (转)
/// AES加密 2 /// </summary> 3 /// <param name="inputdata">输入的数据 ...
- D3D11中的MSAA
这两年我的工作都转到了D3D11,目前新出硬件几乎全部支持此标准,加上D3D11接口清晰,概念直观,等到windows7普及,想必未来都是D3D11的天下.最近时间较空,我陆续开始写些基础文章,希望对 ...
- android 中targetSdkVersion和与target属性的区别
AndroidMenifest.xml中targetSdkVersion和project.properties中的target属性的区别 在AndroidMenifest.xml中,常常会有 ...
- 手机浏览器JS识别
识别方法:采用Fiddler 抓包工具 侦测手机http链接,抓取http头 查看 工具:Fiddler 1:Fiddler配置 允许远程设备连接,配置端口为默认8888(确保8888端口没有被其他进 ...
- 编写高质量JS代码的68个有效方法(九)
No.41.将原型视为实现细节 Tips: 对象是接口,原型是实现 避免检查你无法控制的对象的原型结构 避免检查实现在你无法控制的对象内部的属性 我们可以获取对象的属性值和调用其方法,这些操作都不是特 ...
- Nopcommerce主要的技术
Nopcommerce主要用到的技术及特点: 1.Entity Framework 2.ASP.NET mvc 3.IoC容器+依赖注入(Autofac) 4.使用EF中的EntityTypeConf ...
- 剑指架构师系列-Struts2构造函数的循环依赖注入
Struts2可以完成构造函数的循环依赖注入,来看看Struts2的大师们是怎么做到的吧! 首先定义IBlood与BloodImpl类: public interface IBlood { } pub ...
- iOS- 微信支付 (服务器调起支付 )以及回调不成功的原因 不看后悔
写的不错,给留个言哈... 一. 支付准备工作 1. 微信相关准备工作 (1) 向微信官方开通支付功能. 这个不是前端的工作. (2) 导入官方下载的微信支付SDK包. 我用的是微信开放平台下载的SD ...
- ActiveMQ学习(三)——MQ的通讯模式
1) 点对点通讯:点对点方式是最为传统和常见的通讯方式,它支持一对一.一对多.多对多.多对一等多种配置方式,支持树状.网状等多种拓扑结构. 2) 多点广播:MQ适用于不同类型的应用.其中重要的,也是正 ...