Skip to content

Commit 50c6273

Browse files
tigCopilot
andcommitted
Fixes gui-cs#4051 - Adds cancellable_work_pattern.md (gui-cs#4052)
* touching publish.yml * Updated md files * Updated md files 2 * Updated md files 3 * Updated API docs to point * commmand->command * Update Terminal.Gui/View/View.Command.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 0a23df7 commit 50c6273

File tree

11 files changed

+741
-88
lines changed

11 files changed

+741
-88
lines changed

Examples/UICatalog/Scenarios/Transparent.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ public override void Main ()
2424
appWindow.VerticalTextAlignment = Alignment.Center;
2525
appWindow.ClearingViewport += (s, e) =>
2626
{
27-
appWindow!.FillRect (appWindow!.Viewport, Glyphs.Stipple);
27+
if (s is View sender)
28+
{
29+
sender.FillRect (sender.Viewport, Glyphs.Stipple);
30+
}
31+
2832
e.Cancel = true;
2933
};
3034
ViewportSettingsEditor viewportSettingsEditor = new ViewportSettingsEditor ()

Terminal.Gui/Input/Command.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ namespace Terminal.Gui;
1010
/// <seealso cref="View.MouseBindings"/>
1111
/// <seealso cref="Application.KeyBindings"/>
1212
/// <remarks>
13-
/// <see cref="Application"/> supports a subset of these commands by default, which can be overriden via <see cref="Application.KeyBindings"/>.
13+
/// <para>
14+
/// <see cref="Application"/> supports a subset of these commands by default, which can be overriden via <see cref="Application.KeyBindings"/>.
15+
/// </para>
16+
/// <para>
17+
/// See the Commands Deep Dive for more information: <see href="https://gui-cs.github.io/Terminal.GuiV2Docs/docs/command.html"/>.
18+
/// </para>
1419
/// </remarks>
1520
public enum Command
1621
{

Terminal.Gui/View/View.Command.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ private void SetupCommands ()
6868

6969
// Best practice is to invoke the virtual method first.
7070
// This allows derived classes to handle the event and potentially cancel it.
71+
// For robustness' sake, even if the virtual method returns true, if the args
72+
// indicate the event should be cancelled, we honor that.
7173
if (OnCommandNotBound (args) || args.Cancel)
7274
{
7375
return true;
@@ -299,6 +301,9 @@ private void SetupCommands ()
299301
/// <para>
300302
/// This version of AddCommand is for commands that require <see cref="ICommandContext"/>.
301303
/// </para>
304+
/// <para>
305+
/// See the Commands Deep Dive for more information: <see href="https://gui-cs.github.io/Terminal.GuiV2Docs/docs/command.html"/>.
306+
/// </para>
302307
/// </remarks>
303308
/// <param name="command">The command.</param>
304309
/// <param name="impl">The delegate.</param>
@@ -320,6 +325,9 @@ private void SetupCommands ()
320325
/// If the command requires context, use
321326
/// <see cref="AddCommand(Command,CommandImplementation)"/>
322327
/// </para>
328+
/// <para>
329+
/// See the Commands Deep Dive for more information: <see href="https://gui-cs.github.io/Terminal.GuiV2Docs/docs/command.html"/>.
330+
/// </para>
323331
/// </remarks>
324332
/// <param name="command">The command.</param>
325333
/// <param name="impl">The delegate.</param>

docfx/docs/View.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
* *Parent View* - A view that holds a reference to another view in a parent/child relationship, but is NOT a SuperView of the child. Terminal.Gui uses the terms "Child" and "Parent" sparingly. Generally SubView/SuperView is preferred.
1616

17+
### Commands
18+
19+
See the [Command Deep Dive](command.md).
20+
1721
### Input
1822

1923
See the [Keyboard Deep Dive](keyboard.md) and [Mouse Deep Dive](mouse.md).

docfx/docs/command.md

Lines changed: 683 additions & 0 deletions
Large diffs are not rendered by default.

docfx/docs/drawing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The @Terminal.Gui.Application MainLoop will iterate over all Views in the view h
4444
12) DrawComplete is raised.
4545
13) The current View's Frame NOT INCLUDING the Margin is excluded from the current Clip region.
4646

47-
Most of the steps above can be overridden by developers using the standard [Terminal.Gui cancellable event pattern](events.md). For example, the base @Terminal.Gui.View always clears the viewport. To override this, a subclass can override @Terminal.Gui.View.OnClearingViewport to simply return `true`. Or, a user of `View` can subscribe to the @Terminal.Gui.View.ClearingViewport event and set the `Cancel` argument to `true`.
47+
Most of the steps above can be overridden by developers using the standard [Terminal.Gui Cancellable Work Pattern](cancellable_work_pattern.md). For example, the base @Terminal.Gui.View always clears the viewport. To override this, a subclass can override @Terminal.Gui.View.OnClearingViewport to simply return `true`. Or, a user of `View` can subscribe to the @Terminal.Gui.View.ClearingViewport event and set the `Cancel` argument to `true`.
4848

4949
Then, after the above steps have completed, the Mainloop will iterate through all views in the view hierarchy again, this time calling Draw on any @Terminal.Gui.View.Margin objects, using the cached Clip region mentioned above. This enables Margin to be transparent.
5050

docfx/docs/events.md

Lines changed: 16 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
Terminal.Gui exposes and uses events in many places. This deep dive covers the patterns used, where they are used, and notes any exceptions.
44

5+
## See Also
6+
7+
* [Cancellable Work Pattern](cancellable_work_pattern.md)
8+
* [Command Deep Dive](command.md)
9+
510
## Tenets for Terminal.Gui Events (Unless you know better ones...)
611

712
Tenets higher in the list have precedence over tenets lower in the list.
@@ -29,98 +34,24 @@ Tenets higher in the list have precedence over tenets lower in the list.
2934

3035
TG follows the *naming* advice provided in [.NET Naming Guidelines - Names of Events](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-type-members?redirectedfrom=MSDN#names-of-events).
3136

32-
## `EventHandler` style event best-practices
37+
## Common Event Patterns
38+
39+
### OnEvent/Event
40+
41+
The primary pattern for events is the `OnEvent/Event` idiom.
3342

3443
* Implement a helper method for raising the event: `RaisexxxEvent`.
3544
* If the event is cancelable, the return type should be either `bool` or `bool?`.
3645
* Can be `private`, `internal`, or `public` depending on the situation. `internal` should only be used to enable unit tests.
37-
* Raising an event involves FIRST calling the `protected virtual` method, THEN invoking the `EventHandler.
38-
39-
## `Action<T>` style callback best-practices
40-
41-
- tbd
42-
43-
## `INotifyPropertyChanged` style notification best practices
44-
45-
- tbd
46-
47-
## Common Patterns
48-
49-
The primary pattern for events is the `event/EventHandler` idiom. We use the `Action<T>` idiom sparingly. We support `INotifyPropertyChanged` in cases where data binding is relevant.
50-
51-
52-
53-
## Cancellable Event Pattern
54-
55-
A cancellable event is really two events and some activity that takes place between those events. The "pre-event" happens before the activity. The activity then takes place (or not). If the activity takes place, then the "post-event" is typically raised. So, to be precise, no event is being cancelled even though we say we have a cancellable event. Rather, the activity that takes place between the two events is what is cancelled — and likely prevented from starting at all.
56-
57-
### **Before** - If any pre-conditions are met raise the "pre-event", typically named in the form of "xxxChanging". e.g.
58-
59-
- A `protected virtual` method is called. This method is named `OnxxxChanging` and the base implementation simply does `return false`.
60-
- If the `OnxxxChanging` method returns `true` it means a derived class canceled the event. Processing should stop.
61-
- Otherwise, the `xxxChanging` event is invoked via `xxxChanging?.Invoke(args)`. If `args.Cancel/Handled == true` it means a subscriber has cancelled the event. Processing should stop.
62-
63-
64-
### **During** - Do work.
65-
66-
### **After** - Raise the "post-event", typically named in the form of "xxxChanged"
67-
68-
- A `protected virtual` method is called. This method is named `OnxxxChanged` has a return type of `void`.
69-
- The `xxxChanged` event is invoked via `xxxChanging?.Invoke(args)`.
70-
71-
The `OrientationHelper` class supporting `IOrientation` and a `View` having an `Orientation` property illustrates the preferred TG pattern for cancelable events.
72-
73-
```cs
74-
/// <summary>
75-
/// Gets or sets the orientation of the View.
76-
/// </summary>
77-
public Orientation Orientation
78-
{
79-
get => _orientation;
80-
set
81-
{
82-
if (_orientation == value)
83-
{
84-
return;
85-
}
86-
87-
// Best practice is to call the virtual method first.
88-
// This allows derived classes to handle the event and potentially cancel it.
89-
if (_owner?.OnOrientationChanging (value, _orientation) ?? false)
90-
{
91-
return;
92-
}
93-
94-
// If the event is not canceled by the virtual method, raise the event to notify any external subscribers.
95-
CancelEventArgs<Orientation> args = new (in _orientation, ref value);
96-
OrientationChanging?.Invoke (_owner, args);
97-
98-
if (args.Cancel)
99-
{
100-
return;
101-
}
102-
103-
// If the event is not canceled, update the value.
104-
Orientation old = _orientation;
46+
* Raising an event involves FIRST calling the `protected virtual` method, THEN invoking
47+
the `EventHandler`.
10548

106-
if (_orientation != value)
107-
{
108-
_orientation = value;
49+
### Action
10950

110-
if (_owner is { })
111-
{
112-
_owner.Orientation = value;
113-
}
114-
}
51+
We use the `Action<T>` idiom sparingly.
11552

116-
// Best practice is to call the virtual method first, then raise the event.
117-
_owner?.OnOrientationChanged (_orientation);
118-
OrientationChanged?.Invoke (_owner, new (in _orientation));
119-
}
120-
}
121-
```
53+
### INotifyPropertyChanged
12254

123-
## `bool` or `bool?`
55+
We support `INotifyPropertyChanged` in cases where data binding is relevant.
12456

125-
12657

docfx/docs/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ See [What's New in V2 For more](newinv2.md).
2121
## Conceptual Documentation
2222

2323
* [Arrangement API](arrangement.md)
24+
* [Cancellable Work Pattern](cancellable_work_pattern.md)
2425
* [Configuration and Theme Manager](config.md)
26+
* [Command Deep Dive](command.md)
2527
* [Cursor Deep Dive](cursor.md)
2628
* [Cross-platform Driver Model](drivers.md)
2729
* [Dim.Auto Deep Dive](dimauto.md)

docfx/docs/keyboard.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Keyboard Deep Dive
22

3+
## See Also
4+
5+
* [Cancellable Work Pattern](cancellable_work_pattern.md)
6+
* [Command Deep Dive](command.md)
7+
38
## Tenets for Terminal.Gui Keyboard Handling (Unless you know better ones...)
49

510
Tenets higher in the list have precedence over tenets lower in the list.

docfx/docs/mouse.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Mouse API
22

3+
## See Also
4+
5+
* [Cancellable Work Pattern](cancellable_work_pattern.md)
6+
* [Command Deep Dive](command.md)
7+
8+
9+
310
## Tenets for Terminal.Gui Mouse Handling (Unless you know better ones...)
411

512
Tenets higher in the list have precedence over tenets lower in the list.

0 commit comments

Comments
 (0)