diff --git a/GrasshopperAsyncComponent/GH_AsyncComponent.cs b/GrasshopperAsyncComponent/GH_AsyncComponent.cs index 33179f9..6caf97e 100755 --- a/GrasshopperAsyncComponent/GH_AsyncComponent.cs +++ b/GrasshopperAsyncComponent/GH_AsyncComponent.cs @@ -86,6 +86,24 @@ namespace GrasshopperAsyncComponent Tasks = new List(); } + public void RequestCancellation() + { + foreach(var token in CancellationSources) + { + token.Cancel(); + } + + CancellationSources.Clear(); + Workers.Clear(); + ProgressReports.Clear(); + Tasks.Clear(); + + Interlocked.Exchange(ref SetData, 0); + + Message = "Done"; + OnDisplayExpired(true); + } + public virtual void DisplayProgress(object sender, System.Timers.ElapsedEventArgs e) { if (Workers.Count == 0) diff --git a/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj b/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj index 8a8db8d..c48c592 100755 --- a/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj +++ b/GrasshopperAsyncComponent/GrasshopperAsyncComponent.csproj @@ -4,7 +4,7 @@ Debug AnyCPU - {695D2B91-DDB6-416E-8A99-DDE6253DA7AA} + {114D5E49-AC13-47F7-A70E-B4289579F4E3} Library Properties GrasshopperAsyncComponent diff --git a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs index 0cd09e1..b916f96 100755 --- a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs +++ b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using GrasshopperAsyncComponent; +using System.Windows.Forms; namespace GrasshopperAsyncComponentDemo.SampleImplementations { @@ -30,7 +31,15 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations protected override void RegisterOutputParams(GH_OutputParamManager pManager) { pManager.AddNumberParameter("Output", "O", "The n-th prime number.", GH_ParamAccess.item); + } + protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu) + { + base.AppendAdditionalComponentMenuItems(menu); + Menu_AppendItem(menu, "Cancel", (s, e) => + { + this.RequestCancellation(); + }); } } @@ -44,7 +53,7 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations public override void DoWork(Action ReportProgress, Action Done) { // 👉 Checking for cancellation! - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { Done(); return; } int count = 0; long a = 2; @@ -53,14 +62,14 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations while (count < TheNthPrime) { // 👉 Checking for cancellation! - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { Done(); return; } long b = 2; int prime = 1;// to check if found a prime while (b * b <= a) { // 👉 Checking for cancellation! - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { Done(); return; } if (a % b == 0) { @@ -98,7 +107,7 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations public override void SetData(IGH_DataAccess DA) { // 👉 Checking for cancellation! - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { return; } DA.SetData(0, ThePrime); } diff --git a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs index b204825..2f63da4 100755 --- a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs +++ b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using GrasshopperAsyncComponent; +using System.Windows.Forms; namespace GrasshopperAsyncComponentDemo.SampleImplementations { @@ -31,6 +32,15 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations { pManager.AddTextParameter("Output", "O", "Nothing really interesting.", GH_ParamAccess.item); } + + protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu) + { + base.AppendAdditionalComponentMenuItems(menu); + Menu_AppendItem(menu, "Cancel", (s, e) => + { + this.RequestCancellation(); + }); + } } public class UselessCyclesWorker : WorkerInstance @@ -42,7 +52,7 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations public override void DoWork(Action ReportProgress, Action Done) { // Checking for cancellation - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { Done(); return; } for (int i = 0; i <= MaxIterations; i++) { @@ -53,7 +63,7 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations ReportProgress(Id, ((double)(i + 1) / (double)MaxIterations)); // Checking for cancellation - if (CancellationToken.IsCancellationRequested) return; + if (CancellationToken.IsCancellationRequested) { Done(); return; } } Done(); diff --git a/README.md b/README.md index 28a42c8..664f5a1 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,23 @@ Q: Does this component use all my cores? A: OH YES. It goes WROOOM. ![image](https://user-images.githubusercontent.com/7696515/95597125-29310900-0a46-11eb-99ce-663b34506a7a.png) +Q: Can I cancel a stuff that's in progress? + +A: Yes. The `GH_AsyncComponent` class now exposes the `RequestCancellation()` method, which you can invoke from a custom menu action, or however you want. Note, to properly handle this and ensure the component's inner flow state is properly reset, when respecting the cancellation in your component, you should call the `Done()` function before returning from `DoWork()`. E.g.: + +```cs + +public override void DoWork(Action ReportProgress, Action Done) +{ + // note: call done from inside DoWork(), then return abruptly. + if (CancellationToken.IsCancellationRequested) { Done(); return; } + // more code +} + +``` + + + ### Debugging Quite easy: