diff --git a/GrasshopperAsyncComponent/GH_AsyncComponent.cs b/GrasshopperAsyncComponent/GH_AsyncComponent.cs index 6caf97e..d32e72f 100755 --- a/GrasshopperAsyncComponent/GH_AsyncComponent.cs +++ b/GrasshopperAsyncComponent/GH_AsyncComponent.cs @@ -106,7 +106,7 @@ namespace GrasshopperAsyncComponent public virtual void DisplayProgress(object sender, System.Timers.ElapsedEventArgs e) { - if (Workers.Count == 0) + if (Workers.Count == 0 || ProgressReports.Values.Count == 0) { return; } @@ -244,5 +244,24 @@ namespace GrasshopperAsyncComponent Message = "Done"; OnDisplayExpired(true); } + + public void RequestCancellation() + { + foreach (var source in CancellationSources) + { + source.Cancel(); + } + + CancellationSources.Clear(); + Workers.Clear(); + ProgressReports.Clear(); + Tasks.Clear(); + + Interlocked.Exchange(ref State, 0); + Interlocked.Exchange(ref SetData, 0); + Message = "Cancelled"; + OnDisplayExpired(true); + } + } } diff --git a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs index b916f96..105cc9c 100755 --- a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs +++ b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_PrimeCalculatorAsyncComponent.cs @@ -41,6 +41,15 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations this.RequestCancellation(); }); } + + public override void AppendAdditionalMenuItems(ToolStripDropDown menu) + { + base.AppendAdditionalMenuItems(menu); + Menu_AppendItem(menu, "Cancel", (s, e) => + { + RequestCancellation(); + }); + } } public class PrimeCalculatorWorker : WorkerInstance diff --git a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs index 2f63da4..498b144 100755 --- a/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs +++ b/GrasshopperAsyncComponentDemo/SampleImplementations/Sample_UslessCyclesComponent.cs @@ -33,12 +33,12 @@ namespace GrasshopperAsyncComponentDemo.SampleImplementations pManager.AddTextParameter("Output", "O", "Nothing really interesting.", GH_ParamAccess.item); } - protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu) + public override void AppendAdditionalMenuItems(ToolStripDropDown menu) { - base.AppendAdditionalComponentMenuItems(menu); + base.AppendAdditionalMenuItems(menu); Menu_AppendItem(menu, "Cancel", (s, e) => { - this.RequestCancellation(); + RequestCancellation(); }); } } diff --git a/README.md b/README.md index 664f5a1..9ca7383 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Looks nice, doesn't it? Notice that the solution runs "eagerly" - every time the - **Grasshopper and Rhino are still responsive!** - **There's progress reporting!** (personally I hate waiting for Gh to unfreeze...). +- **Thread safe**: 99% of the times this won't explode in your face. It still might though! ### Approach @@ -46,18 +47,20 @@ 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? +Q: Can I enable cancellation of a longer running task? -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.: +A: Yes, now you can! In your component, just add a right click menu action like so: ```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 -} + public override void AppendAdditionalMenuItems(ToolStripDropDown menu) + { + base.AppendAdditionalMenuItems(menu); + Menu_AppendItem(menu, "Cancel", (s, e) => + { + RequestCancellation(); + }); + } ```