[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类别。

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

问题情景01

解决方案

处理跨平台的定时执行功能,其实解决方案很简单,只要建立一个跨平台的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);
            }
        }
    }
    
  • 执行结果

    使用范例01

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);
            }
        }
    }
    
  • 执行结果

    使用范例03

posted @ 2013-11-24 20:07  Clark159  阅读(285)  评论(0编辑  收藏  举报