OrientationHelper.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #nullable enable
  2. namespace Terminal.Gui;
  3. /// <summary>
  4. /// Helper class for implementing <see cref="IOrientation"/>.
  5. /// </summary>
  6. /// <remarks>
  7. /// <para>
  8. /// Implements the standard pattern for changing/changed events.
  9. /// </para>
  10. /// </remarks>
  11. /// <example>
  12. /// <code>
  13. /// private class OrientedView : View, IOrientation
  14. /// {
  15. /// private readonly OrientationHelper _orientationHelper;
  16. ///
  17. /// public OrientedView ()
  18. /// {
  19. /// _orientationHelper = new (this);
  20. /// Orientation = Orientation.Vertical;
  21. /// _orientationHelper.OrientationChanging += (sender, e) =&gt; OrientationChanging?.Invoke (this, e);
  22. /// _orientationHelper.OrientationChanged += (sender, e) =&gt; OrientationChanged?.Invoke (this, e);
  23. /// }
  24. ///
  25. /// public Orientation Orientation
  26. /// {
  27. /// get =&gt; _orientationHelper.Orientation;
  28. /// set =&gt; _orientationHelper.Orientation = value;
  29. /// }
  30. ///
  31. /// public event EventHandler&lt;CancelEventArgs&lt;Orientation&gt;&gt; OrientationChanging;
  32. /// public event EventHandler&lt;EventArgs&lt;Orientation&gt;&gt; OrientationChanged;
  33. ///
  34. /// public bool OnOrientationChanging (Orientation currentOrientation, Orientation newOrientation)
  35. /// {
  36. /// // Custom logic before orientation changes
  37. /// return false; // Return true to cancel the change
  38. /// }
  39. ///
  40. /// public void OnOrientationChanged (Orientation newOrientation)
  41. /// {
  42. /// // Custom logic after orientation has changed
  43. /// }
  44. /// }
  45. /// </code>
  46. /// </example>
  47. public class OrientationHelper
  48. {
  49. private Orientation _orientation;
  50. private readonly IOrientation _owner;
  51. /// <summary>
  52. /// Initializes a new instance of the <see cref="OrientationHelper"/> class.
  53. /// </summary>
  54. /// <param name="owner">Specifies the object that owns this helper instance and implements <see cref="IOrientation"/>.</param>
  55. public OrientationHelper (IOrientation owner) { _owner = owner; }
  56. /// <summary>
  57. /// Gets or sets the orientation of the View.
  58. /// </summary>
  59. public Orientation Orientation
  60. {
  61. get => _orientation;
  62. set
  63. {
  64. if (_orientation == value)
  65. {
  66. return;
  67. }
  68. // Best practice is to invoke the virtual method first.
  69. // This allows derived classes to handle the event and potentially cancel it.
  70. if (_owner?.OnOrientationChanging (value, _orientation) ?? false)
  71. {
  72. return;
  73. }
  74. // If the event is not canceled by the virtual method, raise the event to notify any external subscribers.
  75. CancelEventArgs<Orientation> args = new (in _orientation, ref value);
  76. OrientationChanging?.Invoke (_owner, args);
  77. if (args.Cancel)
  78. {
  79. return;
  80. }
  81. // If the event is not canceled, update the value.
  82. Orientation old = _orientation;
  83. if (_orientation != value)
  84. {
  85. _orientation = value;
  86. if (_owner is { })
  87. {
  88. _owner.Orientation = value;
  89. }
  90. }
  91. // Best practice is to invoke the virtual method first.
  92. _owner?.OnOrientationChanged (_orientation);
  93. // Even though Changed is not cancelable, it is still a good practice to raise the event after.
  94. OrientationChanged?.Invoke (_owner, new (in _orientation));
  95. }
  96. }
  97. /// <summary>
  98. /// Raised when the orientation is changing. This is cancelable.
  99. /// </summary>
  100. /// <remarks>
  101. /// <para>
  102. /// Views that implement <see cref="IOrientation"/> should raise <see cref="IOrientation.OrientationChanging"/>
  103. /// after the orientation has changed
  104. /// (<code>_orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e);</code>).
  105. /// </para>
  106. /// <para>
  107. /// This event will be raised after the <see cref="IOrientation.OnOrientationChanging"/> method is called (assuming
  108. /// it was not canceled).
  109. /// </para>
  110. /// </remarks>
  111. public event EventHandler<CancelEventArgs<Orientation>>? OrientationChanging;
  112. /// <summary>
  113. /// Raised when the orientation has changed.
  114. /// </summary>
  115. /// <remarks>
  116. /// <para>
  117. /// Views that implement <see cref="IOrientation"/> should raise <see cref="IOrientation.OrientationChanged"/>
  118. /// after the orientation has changed
  119. /// (<code>_orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e);</code>).
  120. /// </para>
  121. /// <para>
  122. /// This event will be raised after the <see cref="IOrientation.OnOrientationChanged"/> method is called.
  123. /// </para>
  124. /// </remarks>
  125. public event EventHandler<EventArgs<Orientation>>? OrientationChanged;
  126. }