OrientationHelper.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. namespace Terminal.Gui;
  2. /// <summary>
  3. /// Helper class for implementing <see cref="IOrientation"/>.
  4. /// </summary>
  5. /// <remarks>
  6. /// <para>
  7. /// Implements the standard pattern for changing/changed events.
  8. /// </para>
  9. /// <para>
  10. /// Views that implement <see cref="IOrientation"/> should add a OrientationHelper property. See <see cref="RadioGroup"/> as an example.
  11. /// </para>
  12. /// </remarks>
  13. public class OrientationHelper
  14. {
  15. private Orientation _orientation = Orientation.Vertical;
  16. private readonly IOrientation _owner;
  17. /// <summary>
  18. /// Initializes a new instance of the <see cref="OrientationHelper"/> class.
  19. /// </summary>
  20. /// <param name="owner">Specifies the object that owns this helper instance.</param>
  21. public OrientationHelper (IOrientation owner) { _owner = owner; }
  22. /// <summary>
  23. /// Gets or sets the orientation of the View.
  24. /// </summary>
  25. public Orientation Orientation
  26. {
  27. get => _orientation;
  28. set
  29. {
  30. if (_orientation == value)
  31. {
  32. return;
  33. }
  34. // Best practice is to invoke the virtual method first.
  35. // This allows derived classes to handle the event and potentially cancel it.
  36. if (_owner?.OnOrientationChanging (value, _orientation) ?? false)
  37. {
  38. return;
  39. }
  40. // If the event is not canceled by the virtual method, raise the event to notify any external subscribers.
  41. CancelEventArgs<Orientation> args = new (in _orientation, ref value);
  42. OrientationChanging?.Invoke (_owner, args);
  43. if (args.Cancel)
  44. {
  45. return;
  46. }
  47. // If the event is not canceled, update the value.
  48. Orientation old = _orientation;
  49. if (_orientation != value)
  50. {
  51. _orientation = value;
  52. if (_owner is { })
  53. {
  54. _owner.Orientation = value;
  55. }
  56. }
  57. // Best practice is to invoke the virtual method first.
  58. _owner?.OnOrientationChanged (old, _orientation);
  59. // Even though Changed is not cancelable, it is still a good practice to raise the event after.
  60. args = new (in old, ref _orientation);
  61. OrientationChanged?.Invoke (_owner, args);
  62. }
  63. }
  64. /// <summary>
  65. /// Raised when the orientation is changing. This is cancelable.
  66. /// </summary>
  67. /// <remarks>
  68. /// <para>
  69. /// Views that implement <see cref="IOrientation"/> should raise <see cref="IOrientation.OrientationChanging"/> after the orientation has changed
  70. /// (<code>_orientationHelper.OrientationChanging += (sender, e) => OrientationChanging?.Invoke (this, e);</code>).
  71. /// </para>
  72. /// <para>
  73. /// This event will be raised after the <see cref="IOrientation.OnOrientationChanging"/> method is called (assuming it was not canceled).
  74. /// </para>
  75. /// </remarks>
  76. public event EventHandler<CancelEventArgs<Orientation>> OrientationChanging;
  77. /// <summary>
  78. /// Raised when the orientation has changed.
  79. /// </summary>
  80. /// <remarks>
  81. /// <para>
  82. /// Views that implement <see cref="IOrientation"/> should raise <see cref="IOrientation.OrientationChanged"/> after the orientation has changed
  83. /// (<code>_orientationHelper.OrientationChanged += (sender, e) => OrientationChanged?.Invoke (this, e);</code>).
  84. /// </para>
  85. /// <para>
  86. /// This event will be raised after the <see cref="IOrientation.OnOrientationChanged"/> method is called.
  87. /// </para>
  88. /// </remarks>
  89. public event EventHandler<CancelEventArgs<Orientation>> OrientationChanged;
  90. }