StyleInstance.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reactive.Subjects;
  4. using Avalonia.Animation;
  5. using Avalonia.Styling.Activators;
  6. #nullable enable
  7. namespace Avalonia.Styling
  8. {
  9. /// <summary>
  10. /// A <see cref="Style"/> which has been instanced on a control.
  11. /// </summary>
  12. internal sealed class StyleInstance : IStyleInstance, IStyleActivatorSink
  13. {
  14. private readonly ISetterInstance[]? _setters;
  15. private readonly IDisposable[]? _animations;
  16. private readonly IStyleActivator? _activator;
  17. private readonly Subject<bool>? _animationTrigger;
  18. public StyleInstance(
  19. IStyle source,
  20. IStyleable target,
  21. IReadOnlyList<ISetter>? setters,
  22. IReadOnlyList<IAnimation>? animations,
  23. IStyleActivator? activator = null)
  24. {
  25. Source = source ?? throw new ArgumentNullException(nameof(source));
  26. Target = target ?? throw new ArgumentNullException(nameof(target));
  27. _activator = activator;
  28. IsActive = _activator is null;
  29. if (setters is not null)
  30. {
  31. var setterCount = setters.Count;
  32. _setters = new ISetterInstance[setterCount];
  33. for (var i = 0; i < setterCount; ++i)
  34. {
  35. _setters[i] = setters[i].Instance(Target);
  36. }
  37. }
  38. if (animations is not null && target is Animatable animatable)
  39. {
  40. var animationsCount = animations.Count;
  41. _animations = new IDisposable[animationsCount];
  42. _animationTrigger = new Subject<bool>();
  43. for (var i = 0; i < animationsCount; ++i)
  44. {
  45. _animations[i] = animations[i].Apply(animatable, null, _animationTrigger);
  46. }
  47. }
  48. }
  49. public bool HasActivator => _activator is not null;
  50. public bool IsActive { get; private set; }
  51. public IStyle Source { get; }
  52. public IStyleable Target { get; }
  53. public void Start()
  54. {
  55. var hasActivator = HasActivator;
  56. if (_setters is not null)
  57. {
  58. foreach (var setter in _setters)
  59. {
  60. setter.Start(hasActivator);
  61. }
  62. }
  63. if (hasActivator)
  64. {
  65. _activator!.Subscribe(this, 0);
  66. }
  67. else if (_animationTrigger is not null)
  68. {
  69. _animationTrigger.OnNext(true);
  70. }
  71. }
  72. public void Dispose()
  73. {
  74. if (_setters is not null)
  75. {
  76. foreach (var setter in _setters)
  77. {
  78. setter.Dispose();
  79. }
  80. }
  81. if (_animations is not null)
  82. {
  83. foreach (var subscription in _animations)
  84. {
  85. subscription.Dispose();
  86. }
  87. }
  88. _activator?.Dispose();
  89. }
  90. private void ActivatorChanged(bool value)
  91. {
  92. if (IsActive != value)
  93. {
  94. IsActive = value;
  95. _animationTrigger?.OnNext(value);
  96. if (_setters is not null)
  97. {
  98. if (IsActive)
  99. {
  100. foreach (var setter in _setters)
  101. {
  102. setter.Activate();
  103. }
  104. }
  105. else
  106. {
  107. foreach (var setter in _setters)
  108. {
  109. setter.Deactivate();
  110. }
  111. }
  112. }
  113. }
  114. }
  115. void IStyleActivatorSink.OnNext(bool value, int tag) => ActivatorChanged(value);
  116. }
  117. }