mirror of
https://github.com/jie65535/GrasscutterCommandGenerator.git
synced 2025-06-07 22:59:14 +08:00
Add Task Page (#166)
This commit is contained in:
parent
0d1bad5551
commit
59af1e468d
@ -50,6 +50,7 @@ namespace GrasscutterTools.Forms
|
||||
this.TCMain = new System.Windows.Forms.TabControl();
|
||||
this.TPMail = new System.Windows.Forms.TabPage();
|
||||
this.MenuSpawnEntityFilter = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.TPLoopTasks = new System.Windows.Forms.TabPage();
|
||||
this.GrpCommand.SuspendLayout();
|
||||
this.TCMain.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
@ -177,6 +178,7 @@ namespace GrasscutterTools.Forms
|
||||
this.TCMain.Controls.Add(this.TPWeapon);
|
||||
this.TCMain.Controls.Add(this.TPManage);
|
||||
this.TCMain.Controls.Add(this.TPMail);
|
||||
this.TCMain.Controls.Add(this.TPLoopTasks);
|
||||
this.TCMain.Controls.Add(this.TPQuest);
|
||||
this.TCMain.Controls.Add(this.TPScene);
|
||||
this.TCMain.Controls.Add(this.TPAbout);
|
||||
@ -194,6 +196,12 @@ namespace GrasscutterTools.Forms
|
||||
this.MenuSpawnEntityFilter.Name = "MenuSpawnEntityFilter";
|
||||
resources.ApplyResources(this.MenuSpawnEntityFilter, "MenuSpawnEntityFilter");
|
||||
//
|
||||
// TPLoopTasks
|
||||
//
|
||||
resources.ApplyResources(this.TPLoopTasks, "TPLoopTasks");
|
||||
this.TPLoopTasks.Name = "TPLoopTasks";
|
||||
this.TPLoopTasks.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// FormMain
|
||||
//
|
||||
resources.ApplyResources(this, "$this");
|
||||
@ -234,5 +242,6 @@ namespace GrasscutterTools.Forms
|
||||
private System.Windows.Forms.TabControl TCMain;
|
||||
private System.Windows.Forms.TabPage TPMail;
|
||||
private System.Windows.Forms.ContextMenuStrip MenuSpawnEntityFilter;
|
||||
private System.Windows.Forms.TabPage TPLoopTasks;
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,7 @@ namespace GrasscutterTools.Forms
|
||||
TPWeapon.Controls.Add(CreatePage<PageGiveWeapon>());
|
||||
TPManage.Controls.Add(CreatePage<PageManagement>());
|
||||
TPMail.Controls.Add(CreatePage<PageMail>());
|
||||
TPLoopTasks.Controls.Add(CreatePage<PageTasks>());
|
||||
TPQuest.Controls.Add(CreatePage<PageQuest>());
|
||||
TPScene.Controls.Add(CreatePage<PageScene>());
|
||||
TPAbout.Controls.Add(CreatePage<PageAbout>());
|
||||
|
@ -316,7 +316,7 @@
|
||||
<value>TCMain</value>
|
||||
</data>
|
||||
<data name=">>TPAbout.ZOrder" xml:space="preserve">
|
||||
<value>12</value>
|
||||
<value>13</value>
|
||||
</data>
|
||||
<data name="TPManage.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 26</value>
|
||||
@ -370,7 +370,7 @@
|
||||
<value>TCMain</value>
|
||||
</data>
|
||||
<data name=">>TPScene.ZOrder" xml:space="preserve">
|
||||
<value>11</value>
|
||||
<value>12</value>
|
||||
</data>
|
||||
<data name="TPItem.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 26</value>
|
||||
@ -508,7 +508,7 @@
|
||||
<value>TCMain</value>
|
||||
</data>
|
||||
<data name=">>TPQuest.ZOrder" xml:space="preserve">
|
||||
<value>10</value>
|
||||
<value>11</value>
|
||||
</data>
|
||||
<data name="TPArtifact.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 26</value>
|
||||
@ -621,6 +621,33 @@
|
||||
<data name=">>TPMail.ZOrder" xml:space="preserve">
|
||||
<value>9</value>
|
||||
</data>
|
||||
<data name="TPLoopTasks.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>4, 26</value>
|
||||
</data>
|
||||
<data name="TPLoopTasks.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
|
||||
<value>3, 3, 3, 3</value>
|
||||
</data>
|
||||
<data name="TPLoopTasks.Size" type="System.Drawing.Size, System.Drawing">
|
||||
<value>652, 245</value>
|
||||
</data>
|
||||
<data name="TPLoopTasks.TabIndex" type="System.Int32, mscorlib">
|
||||
<value>17</value>
|
||||
</data>
|
||||
<data name="TPLoopTasks.Text" xml:space="preserve">
|
||||
<value>循环</value>
|
||||
</data>
|
||||
<data name=">>TPLoopTasks.Name" xml:space="preserve">
|
||||
<value>TPLoopTasks</value>
|
||||
</data>
|
||||
<data name=">>TPLoopTasks.Type" xml:space="preserve">
|
||||
<value>System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</data>
|
||||
<data name=">>TPLoopTasks.Parent" xml:space="preserve">
|
||||
<value>TCMain</value>
|
||||
</data>
|
||||
<data name=">>TPLoopTasks.ZOrder" xml:space="preserve">
|
||||
<value>10</value>
|
||||
</data>
|
||||
<data name="TCMain.Location" type="System.Drawing.Point, System.Drawing">
|
||||
<value>12, 12</value>
|
||||
</data>
|
||||
|
@ -238,6 +238,12 @@
|
||||
<Compile Include="Pages\PageSpawn.Designer.cs">
|
||||
<DependentUpon>PageSpawn.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageTasks.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageTasks.Designer.cs">
|
||||
<DependentUpon>PageTasks.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.zh-TW.Designer.cs">
|
||||
@ -496,6 +502,9 @@
|
||||
<EmbeddedResource Include="Pages\PageSpawn.zh-TW.resx">
|
||||
<DependentUpon>PageSpawn.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\PageTasks.resx">
|
||||
<DependentUpon>PageTasks.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.zh-TW.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.zh-TW.Designer.cs</LastGenOutput>
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@ -51,7 +52,7 @@ namespace GrasscutterTools.Pages
|
||||
/// <param name="args">参数</param>
|
||||
public SetCommandHandler SetCommand { get; set; }
|
||||
|
||||
public delegate Task<bool> RunCommandsHandler(string[] commands);
|
||||
public delegate Task<bool> RunCommandsHandler(params string[] commands);
|
||||
|
||||
/// <summary>
|
||||
/// 运行命令
|
||||
@ -63,6 +64,30 @@ namespace GrasscutterTools.Pages
|
||||
/// </summary>
|
||||
public Func<string> GetCommand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 运行原始命令(未处理的竖线分割命令文本)
|
||||
/// </summary>
|
||||
/// <param name="commands">未处理的竖线分割命令文本</param>
|
||||
/// <returns>是否运行成功</returns>
|
||||
protected async Task<bool> RunRawCommands(string commands)
|
||||
{
|
||||
if (commands.IndexOf('|') == -1)
|
||||
return await RunCommands(FormatCommand(commands));
|
||||
else
|
||||
return await RunCommands(commands.Split('|').Select(it => FormatCommand(it)).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 格式化命令
|
||||
/// (去除收尾空白,替换换行)
|
||||
/// </summary>
|
||||
/// <param name="raw">原始输入</param>
|
||||
/// <returns>格式化后可执行命令</returns>
|
||||
private string FormatCommand(string raw)
|
||||
{
|
||||
return raw.Trim().Replace("\\r", "\r").Replace("\\n", "\n");
|
||||
}
|
||||
|
||||
#endregion - 命令相关 -
|
||||
|
||||
#region - 生命周期事件 -
|
||||
|
250
Source/GrasscutterTools/Pages/PageTasks.Designer.cs
generated
Normal file
250
Source/GrasscutterTools/Pages/PageTasks.Designer.cs
generated
Normal file
@ -0,0 +1,250 @@
|
||||
namespace GrasscutterTools.Pages
|
||||
{
|
||||
partial class PageTasks
|
||||
{
|
||||
/// <summary>
|
||||
/// 必需的设计器变量。
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有正在使用的资源。
|
||||
/// </summary>
|
||||
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region 组件设计器生成的代码
|
||||
|
||||
/// <summary>
|
||||
/// 设计器支持所需的方法 - 不要修改
|
||||
/// 使用代码编辑器修改此方法的内容。
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.GrpTasks = new System.Windows.Forms.GroupBox();
|
||||
this.ListTasks = new System.Windows.Forms.ListView();
|
||||
this.ColTag = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.ColContent = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.ColDelay = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.ColCount = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.GrpTask = new System.Windows.Forms.GroupBox();
|
||||
this.BtnRemove = new System.Windows.Forms.Button();
|
||||
this.BtnAccept = new System.Windows.Forms.Button();
|
||||
this.NUDTriggerCount = new System.Windows.Forms.NumericUpDown();
|
||||
this.LblTriggerCount = new System.Windows.Forms.Label();
|
||||
this.DTPDelay = new System.Windows.Forms.DateTimePicker();
|
||||
this.LblDelay = new System.Windows.Forms.Label();
|
||||
this.TxtTag = new System.Windows.Forms.TextBox();
|
||||
this.LblTag = new System.Windows.Forms.Label();
|
||||
this.GrpTasks.SuspendLayout();
|
||||
this.GrpTask.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUDTriggerCount)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// GrpTasks
|
||||
//
|
||||
this.GrpTasks.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.GrpTasks.Controls.Add(this.ListTasks);
|
||||
this.GrpTasks.Location = new System.Drawing.Point(3, 3);
|
||||
this.GrpTasks.Name = "GrpTasks";
|
||||
this.GrpTasks.Size = new System.Drawing.Size(640, 183);
|
||||
this.GrpTasks.TabIndex = 0;
|
||||
this.GrpTasks.TabStop = false;
|
||||
this.GrpTasks.Text = "任务列表";
|
||||
//
|
||||
// ListTasks
|
||||
//
|
||||
this.ListTasks.AllowColumnReorder = true;
|
||||
this.ListTasks.CheckBoxes = true;
|
||||
this.ListTasks.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.ColTag,
|
||||
this.ColContent,
|
||||
this.ColDelay,
|
||||
this.ColCount});
|
||||
this.ListTasks.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.ListTasks.HideSelection = false;
|
||||
this.ListTasks.Location = new System.Drawing.Point(3, 19);
|
||||
this.ListTasks.MultiSelect = false;
|
||||
this.ListTasks.Name = "ListTasks";
|
||||
this.ListTasks.Size = new System.Drawing.Size(634, 161);
|
||||
this.ListTasks.TabIndex = 0;
|
||||
this.ListTasks.UseCompatibleStateImageBehavior = false;
|
||||
this.ListTasks.View = System.Windows.Forms.View.Details;
|
||||
this.ListTasks.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.ListTasks_ItemChecked);
|
||||
this.ListTasks.SelectedIndexChanged += new System.EventHandler(this.ListTasks_SelectedIndexChanged);
|
||||
//
|
||||
// ColTag
|
||||
//
|
||||
this.ColTag.Text = "标签";
|
||||
this.ColTag.Width = 150;
|
||||
//
|
||||
// ColContent
|
||||
//
|
||||
this.ColContent.Text = "内容";
|
||||
this.ColContent.Width = 330;
|
||||
//
|
||||
// ColDelay
|
||||
//
|
||||
this.ColDelay.Text = "延迟";
|
||||
//
|
||||
// ColCount
|
||||
//
|
||||
this.ColCount.Text = "次数";
|
||||
//
|
||||
// GrpTask
|
||||
//
|
||||
this.GrpTask.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.GrpTask.Controls.Add(this.BtnRemove);
|
||||
this.GrpTask.Controls.Add(this.BtnAccept);
|
||||
this.GrpTask.Controls.Add(this.NUDTriggerCount);
|
||||
this.GrpTask.Controls.Add(this.LblTriggerCount);
|
||||
this.GrpTask.Controls.Add(this.DTPDelay);
|
||||
this.GrpTask.Controls.Add(this.LblDelay);
|
||||
this.GrpTask.Controls.Add(this.TxtTag);
|
||||
this.GrpTask.Controls.Add(this.LblTag);
|
||||
this.GrpTask.Location = new System.Drawing.Point(3, 186);
|
||||
this.GrpTask.Name = "GrpTask";
|
||||
this.GrpTask.Size = new System.Drawing.Size(640, 50);
|
||||
this.GrpTask.TabIndex = 1;
|
||||
this.GrpTask.TabStop = false;
|
||||
this.GrpTask.Text = "任务";
|
||||
//
|
||||
// BtnRemove
|
||||
//
|
||||
this.BtnRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.BtnRemove.Location = new System.Drawing.Point(534, 18);
|
||||
this.BtnRemove.Name = "BtnRemove";
|
||||
this.BtnRemove.Size = new System.Drawing.Size(100, 23);
|
||||
this.BtnRemove.TabIndex = 7;
|
||||
this.BtnRemove.Text = "× 删除";
|
||||
this.BtnRemove.UseVisualStyleBackColor = true;
|
||||
this.BtnRemove.Click += new System.EventHandler(this.BtnRemove_Click);
|
||||
//
|
||||
// BtnAccept
|
||||
//
|
||||
this.BtnAccept.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.BtnAccept.Location = new System.Drawing.Point(428, 18);
|
||||
this.BtnAccept.Name = "BtnAccept";
|
||||
this.BtnAccept.Size = new System.Drawing.Size(100, 23);
|
||||
this.BtnAccept.TabIndex = 6;
|
||||
this.BtnAccept.Text = "√ 确定";
|
||||
this.BtnAccept.UseVisualStyleBackColor = true;
|
||||
this.BtnAccept.Click += new System.EventHandler(this.BtnAccept_Click);
|
||||
//
|
||||
// NUDTriggerCount
|
||||
//
|
||||
this.NUDTriggerCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.NUDTriggerCount.Location = new System.Drawing.Point(372, 19);
|
||||
this.NUDTriggerCount.Maximum = new decimal(new int[] {
|
||||
1000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.NUDTriggerCount.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
-2147483648});
|
||||
this.NUDTriggerCount.Name = "NUDTriggerCount";
|
||||
this.NUDTriggerCount.Size = new System.Drawing.Size(50, 23);
|
||||
this.NUDTriggerCount.TabIndex = 5;
|
||||
this.NUDTriggerCount.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
-2147483648});
|
||||
//
|
||||
// LblTriggerCount
|
||||
//
|
||||
this.LblTriggerCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.LblTriggerCount.AutoSize = true;
|
||||
this.LblTriggerCount.Location = new System.Drawing.Point(334, 22);
|
||||
this.LblTriggerCount.Name = "LblTriggerCount";
|
||||
this.LblTriggerCount.Size = new System.Drawing.Size(32, 17);
|
||||
this.LblTriggerCount.TabIndex = 4;
|
||||
this.LblTriggerCount.Text = "次数";
|
||||
//
|
||||
// DTPDelay
|
||||
//
|
||||
this.DTPDelay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.DTPDelay.CustomFormat = "";
|
||||
this.DTPDelay.Format = System.Windows.Forms.DateTimePickerFormat.Time;
|
||||
this.DTPDelay.Location = new System.Drawing.Point(258, 19);
|
||||
this.DTPDelay.Name = "DTPDelay";
|
||||
this.DTPDelay.ShowUpDown = true;
|
||||
this.DTPDelay.Size = new System.Drawing.Size(70, 23);
|
||||
this.DTPDelay.TabIndex = 3;
|
||||
this.DTPDelay.Value = new System.DateTime(2022, 12, 10, 0, 1, 0, 0);
|
||||
//
|
||||
// LblDelay
|
||||
//
|
||||
this.LblDelay.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.LblDelay.AutoSize = true;
|
||||
this.LblDelay.Location = new System.Drawing.Point(220, 22);
|
||||
this.LblDelay.Name = "LblDelay";
|
||||
this.LblDelay.Size = new System.Drawing.Size(32, 17);
|
||||
this.LblDelay.TabIndex = 2;
|
||||
this.LblDelay.Text = "延迟";
|
||||
//
|
||||
// TxtTag
|
||||
//
|
||||
this.TxtTag.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.TxtTag.Location = new System.Drawing.Point(49, 18);
|
||||
this.TxtTag.Name = "TxtTag";
|
||||
this.TxtTag.Size = new System.Drawing.Size(165, 23);
|
||||
this.TxtTag.TabIndex = 1;
|
||||
//
|
||||
// LblTag
|
||||
//
|
||||
this.LblTag.AutoSize = true;
|
||||
this.LblTag.Location = new System.Drawing.Point(11, 21);
|
||||
this.LblTag.Name = "LblTag";
|
||||
this.LblTag.Size = new System.Drawing.Size(32, 17);
|
||||
this.LblTag.TabIndex = 0;
|
||||
this.LblTag.Text = "标签";
|
||||
//
|
||||
// PageTasks
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.GrpTask);
|
||||
this.Controls.Add(this.GrpTasks);
|
||||
this.Name = "PageTasks";
|
||||
this.GrpTasks.ResumeLayout(false);
|
||||
this.GrpTask.ResumeLayout(false);
|
||||
this.GrpTask.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUDTriggerCount)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox GrpTasks;
|
||||
private System.Windows.Forms.GroupBox GrpTask;
|
||||
private System.Windows.Forms.DateTimePicker DTPDelay;
|
||||
private System.Windows.Forms.Label LblDelay;
|
||||
private System.Windows.Forms.TextBox TxtTag;
|
||||
private System.Windows.Forms.Label LblTag;
|
||||
private System.Windows.Forms.NumericUpDown NUDTriggerCount;
|
||||
private System.Windows.Forms.Label LblTriggerCount;
|
||||
private System.Windows.Forms.Button BtnRemove;
|
||||
private System.Windows.Forms.Button BtnAccept;
|
||||
private System.Windows.Forms.ListView ListTasks;
|
||||
private System.Windows.Forms.ColumnHeader ColTag;
|
||||
private System.Windows.Forms.ColumnHeader ColContent;
|
||||
private System.Windows.Forms.ColumnHeader ColDelay;
|
||||
private System.Windows.Forms.ColumnHeader ColCount;
|
||||
}
|
||||
}
|
265
Source/GrasscutterTools/Pages/PageTasks.cs
Normal file
265
Source/GrasscutterTools/Pages/PageTasks.cs
Normal file
@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using GrasscutterTools.Properties;
|
||||
using GrasscutterTools.Utils;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GrasscutterTools.Pages
|
||||
{
|
||||
internal partial class PageTasks : BasePage
|
||||
{
|
||||
private const string TAG = nameof(PageTasks);
|
||||
|
||||
public PageTasks()
|
||||
{
|
||||
InitializeComponent();
|
||||
ListTasks.FullRowSelect = true;
|
||||
if (DesignMode) return;
|
||||
|
||||
InitTasks();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 循环任务
|
||||
/// </summary>
|
||||
private class LoopTask
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务标签
|
||||
/// </summary>
|
||||
public string Tag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务内容
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 延迟时间(秒)
|
||||
/// </summary>
|
||||
public int DelayS { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发次数 -1为无限循环
|
||||
/// </summary>
|
||||
public int TriggerCount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务列表路径
|
||||
/// </summary>
|
||||
private readonly string TasksJsonPath = Common.GetAppDataFile("Tasks.json");
|
||||
|
||||
/// <summary>
|
||||
/// 任务集合
|
||||
/// </summary>
|
||||
private List<LoopTask> Tasks;
|
||||
|
||||
/// <summary>
|
||||
/// 运行中的任务集合
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, CancellationTokenSource> RunningTasks = new ConcurrentDictionary<string, CancellationTokenSource>();
|
||||
|
||||
/// <summary>
|
||||
/// 初始化任务集合
|
||||
/// </summary>
|
||||
private void InitTasks()
|
||||
{
|
||||
if (File.Exists(TasksJsonPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
Tasks = JsonConvert.DeserializeObject<List<LoopTask>>(File.ReadAllText(TasksJsonPath));
|
||||
ListTasks.Items.AddRange(Tasks.Select(t => TaskToViewItem(t)).ToArray());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Tasks = new List<LoopTask>();
|
||||
Logger.W(TAG, "Parsing Tasks json failed", ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Tasks = new List<LoopTask>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭时触发
|
||||
/// </summary>
|
||||
public override void OnClosed()
|
||||
{
|
||||
// 取消所有正在运行的任务
|
||||
foreach (var cs in RunningTasks.Values)
|
||||
cs.Cancel();
|
||||
// 清空列表
|
||||
RunningTasks.Clear();
|
||||
|
||||
// 保存任务列表
|
||||
File.WriteAllText(TasksJsonPath, JsonConvert.SerializeObject(Tasks));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务转为列表项
|
||||
/// </summary>
|
||||
/// <param name="task">任务</param>
|
||||
/// <returns>列表项</returns>
|
||||
private static ListViewItem TaskToViewItem(LoopTask task) => new ListViewItem(new string[]
|
||||
{
|
||||
task.Tag,
|
||||
task.Content,
|
||||
TimeSpan.FromSeconds(task.DelayS).ToString(),
|
||||
task.TriggerCount.ToString(),
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// 列表选中项改变时触发
|
||||
/// </summary>
|
||||
private void ListTasks_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (ListTasks.SelectedIndices.Count == 0) return;
|
||||
int i = ListTasks.SelectedIndices[0];
|
||||
var task = Tasks[i];
|
||||
TxtTag.Text = task.Tag;
|
||||
DTPDelay.Value = DateTime.Today.Add(TimeSpan.FromSeconds(task.DelayS));
|
||||
NUDTriggerCount.Value = task.TriggerCount;
|
||||
// 设置命令
|
||||
SetCommand(task.Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击确定按钮时触发
|
||||
/// </summary>
|
||||
private void BtnAccept_Click(object sender, EventArgs e)
|
||||
{
|
||||
var tag = TxtTag.Text.Trim();
|
||||
var commands = GetCommand();
|
||||
var delay = DTPDelay.Value.TimeOfDay;
|
||||
var count = (int)NUDTriggerCount.Value;
|
||||
if (string.IsNullOrEmpty(tag) || string.IsNullOrEmpty(commands) || delay.Ticks == 0)
|
||||
{
|
||||
MessageBox.Show(Resources.EmptyInputTip, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找是否已经存在
|
||||
var i = Tasks.FindIndex(t => t.Tag == tag);
|
||||
if (i == -1)
|
||||
{
|
||||
// 新建任务
|
||||
var t = new LoopTask
|
||||
{
|
||||
Tag = tag,
|
||||
Content = commands,
|
||||
DelayS = (int)delay.TotalSeconds,
|
||||
TriggerCount = count,
|
||||
};
|
||||
ListTasks.Items.Add(TaskToViewItem(t));
|
||||
Tasks.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 已存在的任务,确认是否正在运行中
|
||||
if (ListTasks.Items[i].Checked || RunningTasks.ContainsKey(tag))
|
||||
{
|
||||
MessageBox.Show(Resources.TaskRunningCannotOperated, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 否则修改任务内容
|
||||
var task = Tasks[i];
|
||||
task.Content = commands;
|
||||
task.DelayS = (int)delay.TotalSeconds;
|
||||
task.TriggerCount = count;
|
||||
ListTasks.Items[i] = TaskToViewItem(task);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 点击删除按钮时触发
|
||||
/// </summary>
|
||||
private void BtnRemove_Click(object sender, EventArgs e)
|
||||
{
|
||||
var tag = TxtTag.Text.Trim();
|
||||
// 查找是否已经存在
|
||||
var i = Tasks.FindIndex(t => t.Tag == tag);
|
||||
if (i == -1) return;
|
||||
|
||||
if (ListTasks.Items[i].Checked || RunningTasks.ContainsKey(tag))
|
||||
{
|
||||
MessageBox.Show(Resources.TaskRunningCannotOperated, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 删除实例
|
||||
ListTasks.Items.RemoveAt(i);
|
||||
Tasks.RemoveAt(i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务前复选框改变时触发
|
||||
/// </summary>
|
||||
private void ListTasks_ItemChecked(object sender, ItemCheckedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var item = e.Item;
|
||||
if (item.Index < 0 || item.Index >= Tasks.Count)
|
||||
return;
|
||||
var task = Tasks[item.Index];
|
||||
// 先将旧的任务取消
|
||||
if (RunningTasks.TryRemove(task.Tag, out var source))
|
||||
source.Cancel();
|
||||
|
||||
if (item.Checked)
|
||||
{
|
||||
var cancelSource = new CancellationTokenSource();
|
||||
RunningTasks.TryAdd(task.Tag, cancelSource);
|
||||
var token = cancelSource.Token;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.I(TAG, $"Task \"{task.Tag}\" started");
|
||||
// 循环执行命令
|
||||
for (int c = 0;
|
||||
!token.IsCancellationRequested
|
||||
&& (c < task.TriggerCount || task.TriggerCount <= 0);
|
||||
c++)
|
||||
{
|
||||
// 延迟
|
||||
await Task.Delay(task.DelayS * 1000, token);
|
||||
// 使用UI线程执行
|
||||
var ret = Invoke(new Func<string, Task<bool>>(RunRawCommands), task.Content);
|
||||
if (ret is Task<bool> b && b.Result == false)
|
||||
break;
|
||||
// 执行
|
||||
//if (!await RunRawCommands(task.Content))
|
||||
// break;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 任务结束后取消勾选状态
|
||||
BeginInvoke(new Action(() => item.Checked = false));
|
||||
Logger.I(TAG, $"Task \"{task.Tag}\" stoped");
|
||||
}
|
||||
}, token);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.E(TAG, "Start or Stop Task failed.", ex);
|
||||
MessageBox.Show(ex.ToString(), Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
Source/GrasscutterTools/Pages/PageTasks.resx
Normal file
120
Source/GrasscutterTools/Pages/PageTasks.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
@ -1185,6 +1185,15 @@ namespace GrasscutterTools.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 任务已经启动,无法操作 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string TaskRunningCannotOperated {
|
||||
get {
|
||||
return ResourceManager.GetString("TaskRunningCannotOperated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 提示 的本地化字符串。
|
||||
/// </summary>
|
||||
|
@ -294,4 +294,7 @@ Improvement suggestions have been submitted, please use caution to send emails t
|
||||
<data name="All" xml:space="preserve">
|
||||
<value>All</value>
|
||||
</data>
|
||||
<data name="TaskRunningCannotOperated" xml:space="preserve">
|
||||
<value>The task has already started and cannot be operated</value>
|
||||
</data>
|
||||
</root>
|
@ -306,4 +306,7 @@
|
||||
<data name="All" xml:space="preserve">
|
||||
<value>全部</value>
|
||||
</data>
|
||||
<data name="TaskRunningCannotOperated" xml:space="preserve">
|
||||
<value>任务已经启动,无法操作</value>
|
||||
</data>
|
||||
</root>
|
@ -282,4 +282,7 @@
|
||||
<data name="All" xml:space="preserve">
|
||||
<value>Все</value>
|
||||
</data>
|
||||
<data name="TaskRunningCannotOperated" xml:space="preserve">
|
||||
<value>Задача уже запущена и не может быть выполнена</value>
|
||||
</data>
|
||||
</root>
|
@ -288,4 +288,7 @@
|
||||
<data name="All" xml:space="preserve">
|
||||
<value>全部</value>
|
||||
</data>
|
||||
<data name="TaskRunningCannotOperated" xml:space="preserve">
|
||||
<value>任務已經啟動,無法操作</value>
|
||||
</data>
|
||||
</root>
|
Loading…
Reference in New Issue
Block a user