GeometryEffect.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows;
  4. using System.Windows.Media;
  5. using System.Windows.Threading;
  6. namespace HandyControl.Expression.Media;
  7. [TypeConverter(typeof(GeometryEffectConverter))]
  8. public abstract class GeometryEffect : Freezable
  9. {
  10. // ReSharper disable once InconsistentNaming
  11. private static GeometryEffect defaultGeometryEffect;
  12. public static readonly DependencyProperty GeometryEffectProperty =
  13. DependencyProperty.RegisterAttached("GeometryEffect", typeof(GeometryEffect),
  14. typeof(GeometryEffect),
  15. new DrawingPropertyMetadata(DefaultGeometryEffect,
  16. DrawingPropertyMetadataOptions.AffectsRender, OnGeometryEffectChanged));
  17. protected Geometry CachedGeometry;
  18. private bool _effectInvalidated;
  19. static GeometryEffect()
  20. {
  21. DrawingPropertyMetadata.DrawingPropertyChanged +=
  22. delegate (object sender, DrawingPropertyChangedEventArgs args)
  23. {
  24. if (sender is GeometryEffect effect && args.Metadata.AffectsRender)
  25. effect.InvalidateGeometry(InvalidateGeometryReasons.PropertyChanged);
  26. };
  27. }
  28. public static GeometryEffect DefaultGeometryEffect =>
  29. defaultGeometryEffect ?? (defaultGeometryEffect = new NoGeometryEffect());
  30. public Geometry OutputGeometry =>
  31. CachedGeometry;
  32. protected internal DependencyObject Parent { get; private set; }
  33. protected internal virtual void Attach(DependencyObject obj)
  34. {
  35. if (Parent != null) Detach();
  36. _effectInvalidated = true;
  37. CachedGeometry = null;
  38. if (InvalidateParent(obj)) Parent = obj;
  39. }
  40. public new GeometryEffect CloneCurrentValue()
  41. {
  42. return (GeometryEffect) base.CloneCurrentValue();
  43. }
  44. protected override Freezable CreateInstanceCore()
  45. {
  46. return (Freezable) Activator.CreateInstance(GetType());
  47. }
  48. protected abstract GeometryEffect DeepCopy();
  49. protected internal virtual void Detach()
  50. {
  51. _effectInvalidated = true;
  52. CachedGeometry = null;
  53. if (Parent != null)
  54. {
  55. InvalidateParent(Parent);
  56. Parent = null;
  57. }
  58. }
  59. public abstract bool Equals(GeometryEffect geometryEffect);
  60. public static GeometryEffect GetGeometryEffect(DependencyObject obj)
  61. {
  62. return (GeometryEffect) obj.GetValue(GeometryEffectProperty);
  63. }
  64. public bool InvalidateGeometry(InvalidateGeometryReasons reasons)
  65. {
  66. if (_effectInvalidated) return false;
  67. _effectInvalidated = true;
  68. if (reasons != InvalidateGeometryReasons.ParentInvalidated) InvalidateParent(Parent);
  69. return true;
  70. }
  71. private static bool InvalidateParent(DependencyObject parent)
  72. {
  73. if (parent is IShape shape)
  74. {
  75. shape.InvalidateGeometry(InvalidateGeometryReasons.ChildInvalidated);
  76. return true;
  77. }
  78. if (parent is GeometryEffect effect)
  79. {
  80. effect.InvalidateGeometry(InvalidateGeometryReasons.ChildInvalidated);
  81. return true;
  82. }
  83. return false;
  84. }
  85. private static void OnGeometryEffectChanged(DependencyObject obj,
  86. DependencyPropertyChangedEventArgs e)
  87. {
  88. var oldValue = e.OldValue as GeometryEffect;
  89. var newValue = e.NewValue as GeometryEffect;
  90. if (!Equals(oldValue, newValue))
  91. {
  92. if (oldValue != null && obj.Equals(oldValue.Parent)) oldValue.Detach();
  93. if (newValue != null)
  94. {
  95. if (newValue.Parent != null)
  96. {
  97. obj.Dispatcher.BeginInvoke(new Action(() =>
  98. {
  99. var effect = newValue.CloneCurrentValue();
  100. obj.SetValue(GeometryEffectProperty, effect);
  101. }), DispatcherPriority.Send, null);
  102. }
  103. else
  104. {
  105. newValue.Attach(obj);
  106. }
  107. }
  108. }
  109. }
  110. public bool ProcessGeometry(Geometry input)
  111. {
  112. var flag = false;
  113. if (_effectInvalidated)
  114. {
  115. flag |= UpdateCachedGeometry(input);
  116. _effectInvalidated = false;
  117. }
  118. return flag;
  119. }
  120. public static void SetGeometryEffect(DependencyObject obj, GeometryEffect value)
  121. {
  122. obj.SetValue(GeometryEffectProperty, value);
  123. }
  124. protected abstract bool UpdateCachedGeometry(Geometry input);
  125. private class NoGeometryEffect : GeometryEffect
  126. {
  127. protected override GeometryEffect DeepCopy()
  128. {
  129. return new NoGeometryEffect();
  130. }
  131. public override bool Equals(GeometryEffect geometryEffect)
  132. {
  133. if (geometryEffect != null) return geometryEffect is NoGeometryEffect;
  134. return true;
  135. }
  136. protected override bool UpdateCachedGeometry(Geometry input)
  137. {
  138. CachedGeometry = input;
  139. return false;
  140. }
  141. }
  142. }