Files
HandyControl/HandyControl/Expression/Media/GeometryEffect.cs
T
NaBian 4aa4afd292 add CircleProgressBar
thanks to @ghost1372 suggestion
2018-11-01 17:45:45 +08:00

172 lines
5.5 KiB
C#

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
namespace HandyControl.Expression.Media
{
[TypeConverter(typeof(GeometryEffectConverter))]
public abstract class GeometryEffect : Freezable
{
// ReSharper disable once InconsistentNaming
private static GeometryEffect defaultGeometryEffect;
public static readonly DependencyProperty GeometryEffectProperty =
DependencyProperty.RegisterAttached("GeometryEffect", typeof(GeometryEffect),
typeof(GeometryEffect),
new DrawingPropertyMetadata(DefaultGeometryEffect,
DrawingPropertyMetadataOptions.AffectsRender, OnGeometryEffectChanged));
protected Geometry CachedGeometry;
private bool _effectInvalidated;
static GeometryEffect()
{
DrawingPropertyMetadata.DrawingPropertyChanged +=
delegate(object sender, DrawingPropertyChangedEventArgs args)
{
if (sender is GeometryEffect effect && args.Metadata.AffectsRender)
effect.InvalidateGeometry(InvalidateGeometryReasons.PropertyChanged);
};
}
public static GeometryEffect DefaultGeometryEffect =>
defaultGeometryEffect ?? (defaultGeometryEffect = new NoGeometryEffect());
public Geometry OutputGeometry =>
CachedGeometry;
protected internal DependencyObject Parent { get; private set; }
protected internal virtual void Attach(DependencyObject obj)
{
if (Parent != null) Detach();
_effectInvalidated = true;
CachedGeometry = null;
if (InvalidateParent(obj)) Parent = obj;
}
public new GeometryEffect CloneCurrentValue()
{
return (GeometryEffect) base.CloneCurrentValue();
}
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
protected abstract GeometryEffect DeepCopy();
protected internal virtual void Detach()
{
_effectInvalidated = true;
CachedGeometry = null;
if (Parent != null)
{
InvalidateParent(Parent);
Parent = null;
}
}
public abstract bool Equals(GeometryEffect geometryEffect);
public static GeometryEffect GetGeometryEffect(DependencyObject obj)
{
return (GeometryEffect) obj.GetValue(GeometryEffectProperty);
}
public bool InvalidateGeometry(InvalidateGeometryReasons reasons)
{
if (_effectInvalidated) return false;
_effectInvalidated = true;
if (reasons != InvalidateGeometryReasons.ParentInvalidated) InvalidateParent(Parent);
return true;
}
private static bool InvalidateParent(DependencyObject parent)
{
if (parent is IShape shape)
{
shape.InvalidateGeometry(InvalidateGeometryReasons.ChildInvalidated);
return true;
}
if (parent is GeometryEffect effect)
{
effect.InvalidateGeometry(InvalidateGeometryReasons.ChildInvalidated);
return true;
}
return false;
}
private static void OnGeometryEffectChanged(DependencyObject obj,
DependencyPropertyChangedEventArgs e)
{
var oldValue = e.OldValue as GeometryEffect;
var newValue = e.NewValue as GeometryEffect;
if (!Equals(oldValue, newValue))
{
if (oldValue != null && obj.Equals(oldValue.Parent)) oldValue.Detach();
if (newValue != null)
{
if (newValue.Parent != null)
{
obj.Dispatcher.BeginInvoke(new Action(() =>
{
var effect = newValue.CloneCurrentValue();
obj.SetValue(GeometryEffectProperty, effect);
}), DispatcherPriority.Send, null);
}
else
{
newValue.Attach(obj);
}
}
}
}
public bool ProcessGeometry(Geometry input)
{
var flag = false;
if (_effectInvalidated)
{
flag |= UpdateCachedGeometry(input);
_effectInvalidated = false;
}
return flag;
}
public static void SetGeometryEffect(DependencyObject obj, GeometryEffect value)
{
obj.SetValue(GeometryEffectProperty, value);
}
protected abstract bool UpdateCachedGeometry(Geometry input);
private class NoGeometryEffect : GeometryEffect
{
protected override GeometryEffect DeepCopy()
{
return new NoGeometryEffect();
}
public override bool Equals(GeometryEffect geometryEffect)
{
if (geometryEffect != null) return geometryEffect is NoGeometryEffect;
return true;
}
protected override bool UpdateCachedGeometry(Geometry input)
{
CachedGeometry = input;
return false;
}
}
}
}