本文繼續介紹定時任務 Wpf.Quartz.Demo.3的一些小細節, 代碼也請前往第3節下載。 1.RichTextBox右鍵菜單 <RichTextBox.ContextMenu> <ContextMenu> <MenuItem Header="剪貼" Command="ApplicationC ...
本文繼續介紹定時任務 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(); }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,當自己學習的動力。