本文继续介绍定时任务 Wpf.Quartz.Demo.3的一些小细节, 代码也请前往第3节下载。
1.RichTextBox右键菜单
<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>
其中上面上个是系统默认的,自己要添加,可以自己定义。
2.右键DataGrid,选中该行。
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseRightButtonDown">
<local:ExInvokeCommandAction Command="{Binding PreviewMouseRightComamnd}" CommandParameter="{Binding SelectedItem, ElementName=table}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
private void PreviewMouseRight(object para)
{
RoutedEventArgs e = ((ExCommandParameter)para).EventArgs as RoutedEventArgs;
var treeViewItem = VisualUpwardSearch<UIElement>(e.OriginalSource as DependencyObject) as UIElement;
if (treeViewItem == null) return;
treeViewItem.Focus();
e.Handled = true;
}
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;
}
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(); }
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); }
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(); } } } }
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 } }
具体的请自行查看对应的类。
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,当自己学习的动力。