定時任務 Wpf.Quartz.Demo.4

本文繼續介紹定時任務 Wpf.Quartz.Demo.3的一些小細節, 代碼也請前往第3節下載。html

1.RichTextBox右鍵菜單async

 <RichTextBox.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="剪貼" Command="ApplicationCommands.Cut"/>                     
                    <MenuItem Header="複製" Command="ApplicationCommands.Copy"/>                                         
                    <MenuItem Header="粘貼" Command="ApplicationCommands.Paste"/>                                          
                    <MenuItem Header="清除" Click="MenuItemClear_Click"/>   
                    <MenuItem x:Name="menuPause" Header="暫停" Click="MenuItemPause_Click"/>   
                </ContextMenu>
            </RichTextBox.ContextMenu>ide

其中上面上個是系統默認的,本身要添加,能夠本身定義。post

2.右鍵DataGrid,選中該行。學習

 <i:Interaction.Triggers>
                <i:EventTrigger EventName="PreviewMouseRightButtonDown">
                    <local:ExInvokeCommandAction Command="{Binding PreviewMouseRightComamnd}" CommandParameter="{Binding SelectedItem, ElementName=table}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>ui

private void PreviewMouseRight(object para)
        {
            RoutedEventArgs e = ((ExCommandParameter)para).EventArgs as RoutedEventArgs;
            var treeViewItem = VisualUpwardSearch<UIElement>(e.OriginalSource as DependencyObject) as UIElement;this

            if (treeViewItem == null) return;
            treeViewItem.Focus();
            e.Handled = true;
        }spa

        private static DependencyObject VisualUpwardSearch<M>(DependencyObject source)
        {
            while (source != null && source.GetType() != typeof(M))
            {
                if (source is Visual || source is Visual3D)
                    source = VisualTreeHelper.GetParent(source);
                else
                    source = LogicalTreeHelper.GetParent(source);
            }
            return source;
        }pwa

3.任務的基本接口,主要是系統的啓動,中止等命令設計

public interface IRun:IBaseRunner
    {
        [Newtonsoft.Json.JsonIgnore()]
        Action<string, LogLevel> LogOut { get; set; }

        Task Start();

        Task Stop();

        Task ReStart();

        Task Resume();

        Task Pause();

        Task RunNowOneTime();
    }
IRun

4.任務的設置的接口,主要是任務的配置保存。

 public interface IBaseRunner
    {
        string Name { get; }
        string DisplayName { get; set; }
        string Remark { get; set; }
        string CronExpression { get; set; }
        TriggerState TriggerState { get; set; }
        string SettingStr { get; set; }
        DateTime? NextRunTime { get; }
        DateTime[] NextRunTimes { get; set; }
        DateTime? StartTime { get; set; }
        DateTime? EndTime { get; set; }
        bool IsEdit { get; set; }
        CronSecondSet CronSecondSet { get; set; }
        CronMinuteSet CronMinuteSet { get; set; }
        CronHourSet CronHourSet { get; set; }
        CronDaySet CronDaySet { get; set; }
        CronMonthSet CronMonthSet { get; set; }
        CronWeekSet CronWeekSet { get; set; }
        CronYearSet CronYearSet { get; set; }
        EasyCronSet EasyCronSet { get; set; }
        Mode Mode { get; set; }
        void Info(string message);
        void DEBUG(string message);
        void ERROR(string message);
        void FATAL(string message);
        void WARN(string message);

    }
IBaseRunner

5.任務類,接口IRun的實現。

using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Wpf.Quartz.Converters;

namespace Wpf.Quartz
{
    public class SimpleRunner<T> : BaseRunner,IRun where T : IJob
    {
        public SimpleRunner()
        {
            base.Name = this.Name;
        }

        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        public new string Name
        {
            //get { return GetType().Name; }
            get { return typeof(T).Name; }
        }


        private readonly SemaphoreSlim locker = new SemaphoreSlim(1);

        public virtual async Task Start()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "Start") == false)
            {
                return;
            }
            await locker.WaitAsync();
            try
            {

                if (string.IsNullOrEmpty(CronExpression))//若是爲空,則設置爲馬上執行一次
                {
                    CronExpression = CronHelper.DateTime2Cron(DateTime.Now.AddSeconds(3));
                }
                Info((DisplayName ?? Name) + "開始啓動!");
                TriggerState= await QuartzHelper.Instance.StartJobExecuteByCron<T>(CronExpression, Name, this, this.StartTime, this.EndTime);
                Info((DisplayName ?? Name) + "啓動完畢!");

                NextRunTimes = QuartzHelper.Instance.GetNextRunTime(CronExpression, StartTime, EndTime, 5);
                IsEdit = false;
            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + "啓動失敗!" + ex.Message);
            }
            finally
            {
                TriggerState = await QuartzHelper.Instance.GetJobState(Name);
                locker.Release();
            }
        }

        public virtual async Task ReStart()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "ReStart") == false)
            {
                return;
            }
            await locker.WaitAsync();
            try
            {
                if (string.IsNullOrEmpty(CronExpression))//若是爲空,則設置爲馬上執行一次
                {
                    CronExpression = CronHelper.DateTime2Cron(DateTime.Now.AddSeconds(3));
                }
                Info(DisplayName??Name + "開始從新啓動!");
                TriggerState = await QuartzHelper.Instance.RemoveJob(Name);
                TriggerState = await QuartzHelper.Instance.StartJobExecuteByCron<T>(CronExpression, Name, this, this.StartTime, this.EndTime);
                Info((DisplayName ?? Name) + "從新啓動完畢!");

                NextRunTimes = QuartzHelper.Instance.GetNextRunTime(CronExpression, StartTime, EndTime, 5);
                IsEdit = false;
            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + "從新啓動失敗!" + ex.Message);
            }
            finally
            {
                TriggerState = await QuartzHelper.Instance.GetJobState(Name);
                locker.Release();
            }
        }

        public virtual async Task Pause()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "Pause") == false)
            {
                return;
            }
            try
            {
                Info((DisplayName ?? Name) + "開始暫停!");
                TriggerState = await QuartzHelper.Instance.PauseJob(Name);
                Info((DisplayName ?? Name) + "暫停完畢!");
            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + "暫停失敗!" + ex.Message);
            }
        }

        public virtual async Task Resume()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "Resume") == false)
            {
                return;
            }
            try
            {
                Info((DisplayName ?? Name) + "開始恢復!");
                TriggerState = await QuartzHelper.Instance.ResumeJob(Name);
                Info((DisplayName ?? Name) + "恢復完畢!");
            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + "恢復失敗!" + ex.Message);
            }
        }

        public virtual async Task Stop()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "Stop") == false)
            {
                return;
            }
            try
            {
                Info((DisplayName ?? Name) + "開始中止!");
                TriggerState = await QuartzHelper.Instance.RemoveJob(Name);
                Info((DisplayName ?? Name) + "中止完畢!");               
            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + "中止失敗!" + ex.Message);
            }
        }

        public virtual async Task RunNowOneTime()
        {
            if (StatusEnableConverter.IsEanbleState(TriggerState, "Run") == false)
            {
                return;
            }
            if (locker.CurrentCount == 0)
            {
                Info((DisplayName ?? Name) + "正在執行,請稍後再執行!");
                return;
            }
            await locker.WaitAsync();
            try
            {
                Info((DisplayName ?? Name) + "開始執行一次!");
                ISchedulerFactory sf = new StdSchedulerFactory();
                IScheduler scheduler = await sf.GetScheduler();
                await scheduler.Start();

                IJobDetail job = await scheduler.GetJobDetail(new JobKey(Name, "group1"));
                if (job == null)
                {
                    job = JobBuilder.Create<HelloJob>()
                   .WithIdentity(Name, "group1")
                   .Build();
                }

                ITrigger trigger = await scheduler.GetTrigger(new TriggerKey(Name, "group1"));
                if (trigger == null)
                {
                    trigger = TriggerBuilder.Create()
                       .WithIdentity(Name, "group1")
                       .StartNow()
                       .WithSimpleSchedule(x => x
                       .WithIntervalInSeconds(1))
                       .Build();
                }
              
                await scheduler.ScheduleJob(job, trigger);

                Info((DisplayName ?? Name) + string.Format("執行一次完畢"));

                
                //await Task.Delay(TimeSpan.FromSeconds(5));

                //await scheduler.Shutdown();              

                //SchedulerMetaData metaData = await scheduler.GetMetaData();
                //Info(string.Format("執行完畢{0}個任務.", metaData.NumberOfJobsExecuted));

            }
            catch (Exception ex)
            {
                log.Fatal(ex);
                Info((DisplayName ?? Name) + string.Format("執行一次失敗") + ex.Message);
            }
            finally
            {
                locker.Release();
            }
        }
    }
}
SimpleRunner

6.BaseRunner,主要是設置Cron

using Quartz;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wpf.Quartz.Models;

namespace Wpf.Quartz
{
    public class BaseRunner: BaseLog, INotifyPropertyChanged
    {
        public string Name { get; set;}

        private string displayName;
        public string DisplayName
        {
            get { return displayName; }
            set
            {
                if (displayName != value)
                {
                    displayName = value;
                    OnPropertyChanged("DisplayName");
                }
            }
        }

        private string remark;
        public string Remark
        {
            get { return remark; }
            set
            {
                if (remark != value)
                {
                    remark = value;
                    OnPropertyChanged("Remark");
                }
            }
        }

        private string cronExpression;
        public string CronExpression
        {
            get { return cronExpression; }
            set
            {
                if (cronExpression != value)
                {
                    cronExpression = value;
                    OnPropertyChanged("CronExpression");
                }
            }
        }

        private TriggerState triggerState = TriggerState.None;
        public TriggerState TriggerState
        {
            get { return triggerState; }
            set
            {
                if (triggerState != value)
                {
                    triggerState = value;
                    OnPropertyChanged("TriggerState");
                }
            }
        }

        private string settingStr = "手動執行";
        public string SettingStr
        {
            get { return settingStr; }
            set
            {
                if (settingStr != value)
                {
                    settingStr = value;
                    OnPropertyChanged("SettingStr");
                }
            }
        }

        public DateTime? NextRunTime
        {
            get
            {
                if (NextRunTimes != null && NextRunTimes.Length > 0)
                {
                    return NextRunTimes[0];                  
                }
                else
                {
                    return null;
                }
            }
           
        }

        private DateTime[] nextRunTimes;
        public DateTime[] NextRunTimes
        {
            get { return nextRunTimes; }
            set
            {
                if (nextRunTimes != value)
                {
                    nextRunTimes = value;
                    OnPropertyChanged("NextRunTimes");
                    OnPropertyChanged("NextRunTime");
                }
            }
        }

        private DateTime? startTime;
        public DateTime? StartTime
        {
            get { return startTime; }
            set
            {
                if (startTime != value)
                {
                    startTime = value;
                    OnPropertyChanged("StartTime");
                }
            }
        }

        private DateTime? endTime;
        public DateTime? EndTime
        {
            get { return endTime; }
            set
            {
                if (endTime != value)
                {
                    endTime = value;
                    OnPropertyChanged("EndTime");
                }
            }
        }

        private bool isEdit;
        public bool IsEdit
        {
            get { return isEdit; }
            set
            {
                if (isEdit != value)
                {
                    isEdit = value;
                    OnPropertyChanged("IsEdit");
                }
            }
        }

        public CronSecondSet CronSecondSet { get; set; } = new CronSecondSet();
        public CronMinuteSet CronMinuteSet { get; set; } = new CronMinuteSet();
        public CronHourSet CronHourSet { get; set; } = new CronHourSet();
        public CronDaySet CronDaySet { get; set; } = new CronDaySet();
        public CronMonthSet CronMonthSet { get; set; } = new CronMonthSet();
        public CronWeekSet CronWeekSet { get; set; } = new CronWeekSet();
        public CronYearSet CronYearSet { get; set; } = new CronYearSet();
        public EasyCronSet EasyCronSet { get; set; } = new EasyCronSet();

        private Mode mode;
        public Mode Mode
        {
            get { return mode; }
            set
            {
                if (mode != value)
                {
                    mode = value;
                    OnPropertyChanged("Mode");
                    CronSecondSet.UpdateExpression();
                }
            }
        }

        private SetMode setMode = SetMode.Easy;
        public SetMode SetMode
        {
            get { return setMode; }
            set
            {
                if (setMode != value)
                {
                    setMode = value;
                    OnPropertyChanged("SetMode");
                    CronSecondSet.UpdateExpression();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }

    public class BaseLog
    {
        #region 日誌輸出
        [Newtonsoft.Json.JsonIgnore()]
        public Action<string, LogLevel> LogOut { get; set; }

        public void Info(string message)
        {
            if (LogOut != null)
            {
                App.Current.Dispatcher.Invoke((Action)delegate ()
                {
                    LogOut(message, LogLevel.INFO);
                });
            }
        }

        public void DEBUG(string message)
        {
            if (LogOut != null)
            {
                App.Current.Dispatcher.Invoke((Action)delegate ()
                {
                    LogOut(message, LogLevel.DEBUG);
                });
            }
        }

        public void ERROR(string message)
        {
            if (LogOut != null)
            {
                App.Current.Dispatcher.Invoke((Action)delegate ()
                {
                    LogOut(message, LogLevel.ERROR);
                });
            }
        }

        public void FATAL(string message)
        {
            if (LogOut != null)
            {
                App.Current.Dispatcher.Invoke((Action)delegate ()
                {
                    LogOut(message, LogLevel.FATAL);
                });
            }
        }

        public void WARN(string message)
        {
            if (LogOut != null)
            {
                App.Current.Dispatcher.Invoke((Action)delegate ()
                {
                    LogOut(message, LogLevel.WARN);
                });
            }
        }
        #endregion
    }
}
BaseRunner

具體的請自行查看對應的類。

        public CronSecondSet CronSecondSet { get; set; } = new CronSecondSet();
        public CronMinuteSet CronMinuteSet { get; set; } = new CronMinuteSet();
        public CronHourSet CronHourSet { get; set; } = new CronHourSet();
        public CronDaySet CronDaySet { get; set; } = new CronDaySet();
        public CronMonthSet CronMonthSet { get; set; } = new CronMonthSet();
        public CronWeekSet CronWeekSet { get; set; } = new CronWeekSet();
        public CronYearSet CronYearSet { get; set; } = new CronYearSet();


        public EasyCronSet EasyCronSet { get; set; } = new EasyCronSet();

 

主要代碼就是用戶自定義設置,你們運行程序看效果。

另外,這種設置太專業了,不適合用戶使用,所以設計了用戶經常使用的模式。

是否是簡單友好多了。

至此完結。

 

下次打算寫一個wcf的Demo,當本身學習的動力。

相關文章
相關標籤/搜索