add Screenshot

This commit is contained in:
NaBian committed 2020-03-06 14:36:12 +08:00
1 parent 08ae754ea3
commit 46b1297aa7
28 files changed
+923 -100

No files matched your search

@@ -0,0 +1,13 @@
using System.Windows;
namespace HandyControl.Interactivity
{
public abstract class Behavior<T> : Behavior where T : DependencyObject
{
protected Behavior() : base(typeof(T))
{
}
protected new T AssociatedObject => (T)base.AssociatedObject;
}
}
@@ -0,0 +1,87 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Media.Animation;
namespace HandyControl.Interactivity
{
public abstract class Behavior : Animatable, IAttachedObject
{
private DependencyObject _associatedObject;
private readonly Type _associatedType;
internal Behavior(Type associatedType)
{
_associatedType = associatedType;
}
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected Type AssociatedType
{
get
{
ReadPreamble();
return _associatedType;
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostBehaviorMultipleTimesExceptionMessage);
if (dependencyObject != null && !AssociatedType.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[] {GetType().Name, dependencyObject.GetType().Name, AssociatedType.Name}));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
OnAssociatedObjectChanged();
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
OnAssociatedObjectChanged();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
internal event EventHandler AssociatedObjectChanged;
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
private void OnAssociatedObjectChanged()
{
AssociatedObjectChanged?.Invoke(this, new EventArgs());
}
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
}
@@ -0,0 +1,42 @@
using System.Windows;
namespace HandyControl.Interactivity
{
public sealed class BehaviorCollection : AttachableCollection<Behavior>
{
internal BehaviorCollection()
{
}
protected override void OnAttached()
{
foreach (var behavior in this)
behavior.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var behavior in this)
behavior.Detach();
}
internal override void ItemAdded(Behavior item)
{
if (item == null || AssociatedObject == null)
return;
item.Attach(AssociatedObject);
}
internal override void ItemRemoved(Behavior item)
{
if (((IAttachedObject) item)?.AssociatedObject == null)
return;
item.Detach();
}
protected override Freezable CreateInstanceCore()
{
return new BehaviorCollection();
}
}
}
@@ -0,0 +1,449 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using HandyControl.Data;
namespace HandyControl.Interactivity
{
public sealed class FluidMoveBehavior : FluidMoveBehaviorBase
{
private static readonly DependencyProperty CacheDuringOverlayProperty =
DependencyProperty.RegisterAttached("CacheDuringOverlay", typeof(object),
typeof(FluidMoveBehavior), new PropertyMetadata(null));
public static readonly DependencyProperty DurationProperty = DependencyProperty.Register("Duration",
typeof(Duration), typeof(FluidMoveBehavior),
new PropertyMetadata(new Duration(TimeSpan.FromSeconds(1.0))));
public static readonly DependencyProperty EaseXProperty = DependencyProperty.Register("EaseX",
typeof(IEasingFunction), typeof(FluidMoveBehavior), new PropertyMetadata(null));
public static readonly DependencyProperty EaseYProperty = DependencyProperty.Register("EaseY",
typeof(IEasingFunction), typeof(FluidMoveBehavior), new PropertyMetadata(null));
public static readonly DependencyProperty FloatAboveProperty =
DependencyProperty.Register("FloatAbove", typeof(bool), typeof(FluidMoveBehavior),
new PropertyMetadata(ValueBoxes.TrueBox));
private static readonly DependencyProperty HasTransformWrapperProperty =
DependencyProperty.RegisterAttached("HasTransformWrapper", typeof(bool),
typeof(FluidMoveBehavior), new PropertyMetadata(ValueBoxes.FalseBox));
private static readonly DependencyProperty InitialIdentityTagProperty =
DependencyProperty.RegisterAttached("InitialIdentityTag", typeof(object),
typeof(FluidMoveBehavior), new PropertyMetadata(null));
public static readonly DependencyProperty InitialTagPathProperty =
DependencyProperty.Register("InitialTagPath", typeof(string), typeof(FluidMoveBehavior),
new PropertyMetadata(string.Empty));
public static readonly DependencyProperty InitialTagProperty =
DependencyProperty.Register("InitialTag", typeof(TagType), typeof(FluidMoveBehavior),
new PropertyMetadata(TagType.Element));
private static readonly DependencyProperty OverlayProperty =
DependencyProperty.RegisterAttached("Overlay", typeof(object), typeof(FluidMoveBehavior),
new PropertyMetadata(null));
private static readonly Dictionary<object, Storyboard> TransitionStoryboardDictionary =
new Dictionary<object, Storyboard>();
public Duration Duration
{
get =>
(Duration) GetValue(DurationProperty);
set => SetValue(DurationProperty, value);
}
public IEasingFunction EaseX
{
get =>
(IEasingFunction) GetValue(EaseXProperty);
set => SetValue(EaseXProperty, value);
}
public IEasingFunction EaseY
{
get =>
(IEasingFunction) GetValue(EaseYProperty);
set => SetValue(EaseYProperty, value);
}
public bool FloatAbove
{
get =>
(bool) GetValue(FloatAboveProperty);
set => SetValue(FloatAboveProperty, value);
}
public TagType InitialTag
{
get =>
(TagType) GetValue(InitialTagProperty);
set => SetValue(InitialTagProperty, value);
}
public string InitialTagPath
{
get =>
(string) GetValue(InitialTagPathProperty);
set => SetValue(InitialTagPathProperty, value);
}
protected override bool ShouldSkipInitialLayout
{
get
{
if (!base.ShouldSkipInitialLayout) return InitialTag == TagType.DataContext;
return true;
}
}
private static void AddTransform(FrameworkElement child, Transform transform)
{
if (!(child.RenderTransform is TransformGroup renderTransform))
{
renderTransform = new TransformGroup
{
Children = {child.RenderTransform}
};
child.RenderTransform = renderTransform;
SetHasTransformWrapper(child, true);
}
renderTransform.Children.Add(transform);
}
private Storyboard CreateTransitionStoryboard(FrameworkElement child, bool usingBeforeLoaded,
ref Rect layoutRect, ref Rect currentRect)
{
var duration = Duration;
var storyboard = new Storyboard
{
Duration = duration
};
var num = !usingBeforeLoaded || Math.Abs(layoutRect.Width) < 0.001
? 1.0
: currentRect.Width / layoutRect.Width;
var num2 = !usingBeforeLoaded || Math.Abs(layoutRect.Height) < 0.001
? 1.0
: currentRect.Height / layoutRect.Height;
var num3 = currentRect.Left - layoutRect.Left;
var num4 = currentRect.Top - layoutRect.Top;
var group = new TransformGroup();
var transform = new ScaleTransform
{
ScaleX = num,
ScaleY = num2
};
group.Children.Add(transform);
var transform2 = new TranslateTransform
{
X = num3,
Y = num4
};
group.Children.Add(transform2);
AddTransform(child, group);
var str = "(FrameworkElement.RenderTransform).";
if (child.RenderTransform is TransformGroup renderTransform && GetHasTransformWrapper(child))
{
object obj2 = str;
str = string.Concat(obj2, "(TransformGroup.Children)[", renderTransform.Children.Count - 1,
"].");
}
if (usingBeforeLoaded)
{
if (Math.Abs(num - 1.0) > 0.001)
{
var element = new DoubleAnimation
{
Duration = duration,
From = num,
To = 1.0
};
Storyboard.SetTarget(element, child);
Storyboard.SetTargetProperty(element,
new PropertyPath(str + "(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
element.EasingFunction = EaseX;
storyboard.Children.Add(element);
}
if (Math.Abs(num2 - 1.0) > 0.001)
{
var animation3 = new DoubleAnimation
{
Duration = duration,
From = num2,
To = 1.0
};
Storyboard.SetTarget(animation3, child);
Storyboard.SetTargetProperty(animation3,
new PropertyPath(str + "(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
animation3.EasingFunction = EaseY;
storyboard.Children.Add(animation3);
}
}
if (Math.Abs(num3) > 0.001)
{
var animation5 = new DoubleAnimation
{
Duration = duration,
From = num3,
To = 0.0
};
Storyboard.SetTarget(animation5, child);
Storyboard.SetTargetProperty(animation5,
new PropertyPath(str + "(TransformGroup.Children)[1].(TranslateTransform.X)"));
animation5.EasingFunction = EaseX;
storyboard.Children.Add(animation5);
}
if (Math.Abs(num4) > 0.001)
{
var animation7 = new DoubleAnimation
{
Duration = duration,
From = num4,
To = 0.0
};
Storyboard.SetTarget(animation7, child);
Storyboard.SetTargetProperty(animation7,
new PropertyPath(str + "(TransformGroup.Children)[1].(TranslateTransform.Y)"));
animation7.EasingFunction = EaseY;
storyboard.Children.Add(animation7);
}
return storyboard;
}
protected override void EnsureTags(FrameworkElement child)
{
base.EnsureTags(child);
if (InitialTag == TagType.DataContext &&
!(child.ReadLocalValue(InitialIdentityTagProperty) is BindingExpression))
child.SetBinding(InitialIdentityTagProperty, new Binding(InitialTagPath));
}
private static bool GetHasTransformWrapper(DependencyObject obj)
{
return (bool) obj.GetValue(HasTransformWrapperProperty);
}
private static object GetInitialIdentityTag(DependencyObject obj)
{
return obj.GetValue(InitialIdentityTagProperty);
}
private static object GetOverlay(DependencyObject obj)
{
return obj.GetValue(OverlayProperty);
}
private static Transform GetTransform(FrameworkElement child)
{
if (child.RenderTransform is TransformGroup renderTransform && renderTransform.Children.Count > 0)
return renderTransform.Children[renderTransform.Children.Count - 1];
return new TranslateTransform();
}
private static bool IsClose(double a, double b)
{
return Math.Abs(a - b) < 1E-07;
}
private static bool IsEmptyRect(Rect rect)
{
if (!rect.IsEmpty && !double.IsNaN(rect.Left)) return double.IsNaN(rect.Top);
return true;
}
private static void RemoveTransform(FrameworkElement child)
{
if (child.RenderTransform is TransformGroup renderTransform)
{
if (GetHasTransformWrapper(child))
{
child.RenderTransform = renderTransform.Children[0];
SetHasTransformWrapper(child, false);
}
else
{
renderTransform.Children.RemoveAt(renderTransform.Children.Count - 1);
}
}
}
private static void SetHasTransformWrapper(DependencyObject obj, bool value)
{
obj.SetValue(HasTransformWrapperProperty, value);
}
private static void SetOverlay(DependencyObject obj, object value)
{
obj.SetValue(OverlayProperty, value);
}
private static void TransferLocalValue(FrameworkElement element, DependencyProperty source,
DependencyProperty dest)
{
var obj2 = element.ReadLocalValue(source);
if (obj2 is BindingExpressionBase base2)
element.SetBinding(dest, base2.ParentBindingBase);
else if (obj2 == DependencyProperty.UnsetValue)
element.ClearValue(dest);
else
element.SetValue(dest, element.GetAnimationBaseValue(source));
element.ClearValue(source);
}
internal override void UpdateLayoutTransitionCore(FrameworkElement child, FrameworkElement root,
object tag, TagData newTagData)
{
Rect empty;
var flag = false;
var usingBeforeLoaded = false;
var initialIdentityTag = GetInitialIdentityTag(child);
var flag3 = TagDictionary.TryGetValue(tag, out var data);
if (flag3 && data.InitialTag != initialIdentityTag)
{
flag3 = false;
TagDictionary.Remove(tag);
}
if (!flag3)
{
if (initialIdentityTag != null && TagDictionary.TryGetValue(initialIdentityTag, out var data2))
{
empty = TranslateRect(data2.AppRect, root, newTagData.Parent);
flag = true;
usingBeforeLoaded = true;
}
else
{
empty = Rect.Empty;
}
data = new TagData
{
ParentRect = Rect.Empty,
AppRect = Rect.Empty,
Parent = newTagData.Parent,
Child = child,
Timestamp = DateTime.Now,
InitialTag = initialIdentityTag
};
TagDictionary.Add(tag, data);
}
else if (!Equals(data.Parent, VisualTreeHelper.GetParent(child)))
{
empty = TranslateRect(data.AppRect, root, newTagData.Parent);
flag = true;
}
else
{
empty = data.ParentRect;
}
var originalChild = child;
if (!IsEmptyRect(empty) && !IsEmptyRect(newTagData.ParentRect) &&
(!IsClose(empty.Left, newTagData.ParentRect.Left) ||
!IsClose(empty.Top, newTagData.ParentRect.Top)) || !Equals(child, data.Child) &&
TransitionStoryboardDictionary.ContainsKey(tag))
{
var rect = empty;
var flag4 = false;
if (TransitionStoryboardDictionary.TryGetValue(tag, out var storyboard))
{
var obj3 = GetOverlay(data.Child);
var adorner = (AdornerContainer) obj3;
flag4 = obj3 != null;
var element = data.Child;
if (obj3 != null)
{
if (adorner.Child is Canvas canvas) element = canvas.Children[0] as FrameworkElement;
}
if (!usingBeforeLoaded) rect = GetTransform(element).TransformBounds(rect);
TransitionStoryboardDictionary.Remove(tag);
storyboard.Stop();
RemoveTransform(element);
if (obj3 != null)
{
AdornerLayer.GetAdornerLayer(root).Remove(adorner);
TransferLocalValue(data.Child, CacheDuringOverlayProperty,
UIElement.RenderTransformProperty);
SetOverlay(data.Child, null);
}
}
object overlay = null;
if (flag4 || flag && FloatAbove)
{
var canvas2 = new Canvas
{
Width = newTagData.ParentRect.Width,
Height = newTagData.ParentRect.Height,
IsHitTestVisible = false
};
var rectangle = new Rectangle
{
Width = newTagData.ParentRect.Width,
Height = newTagData.ParentRect.Height,
IsHitTestVisible = false,
Fill = new VisualBrush(child)
};
canvas2.Children.Add(rectangle);
var container2 = new AdornerContainer(child)
{
Child = canvas2
};
overlay = container2;
SetOverlay(originalChild, overlay);
AdornerLayer.GetAdornerLayer(root).Add(container2);
TransferLocalValue(child, UIElement.RenderTransformProperty, CacheDuringOverlayProperty);
child.RenderTransform = new TranslateTransform(-10000.0, -10000.0);
canvas2.RenderTransform = new TranslateTransform(10000.0, 10000.0);
child = rectangle;
}
var parentRect = newTagData.ParentRect;
var transitionStoryboard =
CreateTransitionStoryboard(child, usingBeforeLoaded, ref parentRect, ref rect);
TransitionStoryboardDictionary.Add(tag, transitionStoryboard);
transitionStoryboard.Completed += delegate
{
if (TransitionStoryboardDictionary.TryGetValue(tag, out var storyboard1) &&
Equals(storyboard1, transitionStoryboard))
{
TransitionStoryboardDictionary.Remove(tag);
transitionStoryboard.Stop();
RemoveTransform(child);
child.InvalidateMeasure();
if (overlay != null)
{
AdornerLayer.GetAdornerLayer(root).Remove((AdornerContainer) overlay);
TransferLocalValue(originalChild, CacheDuringOverlayProperty,
UIElement.RenderTransformProperty);
SetOverlay(originalChild, null);
}
}
};
transitionStoryboard.Begin();
}
data.ParentRect = newTagData.ParentRect;
data.AppRect = newTagData.AppRect;
data.Parent = newTagData.Parent;
data.Child = newTagData.Child;
data.Timestamp = newTagData.Timestamp;
}
}
}
@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using HandyControl.Data;
namespace HandyControl.Interactivity
{
public abstract class FluidMoveBehaviorBase : Behavior<FrameworkElement>
{
public static readonly DependencyProperty AppliesToProperty = DependencyProperty.Register("AppliesTo",
typeof(FluidMoveScope), typeof(FluidMoveBehaviorBase), new PropertyMetadata(FluidMoveScope.Self));
protected static readonly DependencyProperty IdentityTagProperty =
DependencyProperty.RegisterAttached("IdentityTag", typeof(object), typeof(FluidMoveBehaviorBase),
new PropertyMetadata(null));
public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive",
typeof(bool), typeof(FluidMoveBehaviorBase), new PropertyMetadata(ValueBoxes.TrueBox));
private static DateTime LastPurgeTick = DateTime.MinValue;
private static readonly TimeSpan MinTickDelta = TimeSpan.FromSeconds(0.5);
private static DateTime NextToLastPurgeTick = DateTime.MinValue;
internal static Dictionary<object, TagData> TagDictionary = new Dictionary<object, TagData>();
public static readonly DependencyProperty TagPathProperty = DependencyProperty.Register("TagPath",
typeof(string), typeof(FluidMoveBehaviorBase), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty TagProperty = DependencyProperty.Register("Tag",
typeof(TagType), typeof(FluidMoveBehaviorBase), new PropertyMetadata(TagType.Element));
public FluidMoveScope AppliesTo
{
get =>
(FluidMoveScope) GetValue(AppliesToProperty);
set => SetValue(AppliesToProperty, value);
}
public bool IsActive
{
get =>
(bool) GetValue(IsActiveProperty);
set => SetValue(IsActiveProperty, value);
}
protected virtual bool ShouldSkipInitialLayout =>
Tag == TagType.DataContext;
public TagType Tag
{
get =>
(TagType) GetValue(TagProperty);
set => SetValue(TagProperty, value);
}
public string TagPath
{
get =>
(string) GetValue(TagPathProperty);
set => SetValue(TagPathProperty, value);
}
private void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
{
if (IsActive)
{
if (DateTime.Now - LastPurgeTick >= MinTickDelta)
{
List<object> list = null;
foreach (var pair in TagDictionary)
if (pair.Value.Timestamp < NextToLastPurgeTick)
{
if (list == null) list = new List<object>();
list.Add(pair.Key);
}
if (list != null)
foreach (var obj2 in list)
TagDictionary.Remove(obj2);
NextToLastPurgeTick = LastPurgeTick;
LastPurgeTick = DateTime.Now;
}
if (AppliesTo == FluidMoveScope.Self)
{
UpdateLayoutTransition(AssociatedObject);
}
else
{
if (AssociatedObject is Panel associatedObject)
foreach (FrameworkElement element in associatedObject.Children)
UpdateLayoutTransition(element);
}
}
}
protected virtual void EnsureTags(FrameworkElement child)
{
if (Tag == TagType.DataContext &&
!(child.ReadLocalValue(IdentityTagProperty) is BindingExpression))
child.SetBinding(IdentityTagProperty, new Binding(TagPath));
}
protected static object GetIdentityTag(DependencyObject obj)
{
return obj.GetValue(IdentityTagProperty);
}
private static FrameworkElement GetVisualRoot(FrameworkElement child)
{
while (true)
{
if (!(VisualTreeHelper.GetParent(child) is FrameworkElement parent)) return child;
if (AdornerLayer.GetAdornerLayer(parent) == null) return child;
child = parent;
}
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
}
protected static void SetIdentityTag(DependencyObject obj, object value)
{
obj.SetValue(IdentityTagProperty, value);
}
internal static Rect TranslateRect(Rect rect, FrameworkElement from, FrameworkElement to)
{
if (from == null || to == null) return rect;
var point = new Point(rect.Left, rect.Top);
point = from.TransformToVisual(to).Transform(point);
return new Rect(point.X, point.Y, rect.Width, rect.Height);
}
private void UpdateLayoutTransition(FrameworkElement child)
{
if (child.Visibility != Visibility.Collapsed && child.IsLoaded || !ShouldSkipInitialLayout)
{
var visualRoot = GetVisualRoot(child);
var newTagData = new TagData
{
Parent = VisualTreeHelper.GetParent(child) as FrameworkElement,
ParentRect = ExtendedVisualStateManager.GetLayoutRect(child),
Child = child,
Timestamp = DateTime.Now
};
try
{
newTagData.AppRect = TranslateRect(newTagData.ParentRect, newTagData.Parent, visualRoot);
}
catch (ArgumentException)
{
if (ShouldSkipInitialLayout) return;
}
EnsureTags(child);
var identityTag = GetIdentityTag(child) ?? child;
UpdateLayoutTransitionCore(child, visualRoot, identityTag, newTagData);
}
}
internal abstract void UpdateLayoutTransitionCore(FrameworkElement child, FrameworkElement root,
object tag, TagData newTagData);
internal class TagData
{
public Rect AppRect { get; set; }
public FrameworkElement Child { get; set; }
public object InitialTag { get; set; }
public FrameworkElement Parent { get; set; }
public Rect ParentRect { get; set; }
public DateTime Timestamp { get; set; }
}
}
}
@@ -0,0 +1,353 @@
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using HandyControl.Data;
namespace HandyControl.Interactivity
{
public class MouseDragElementBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty ConstrainToParentBoundsProperty =
DependencyProperty.Register("ConstrainToParentBounds", typeof(bool), typeof(MouseDragElementBehavior),
new PropertyMetadata(ValueBoxes.FalseBox, OnConstrainToParentBoundsChanged));
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double),
typeof(MouseDragElementBehavior), new PropertyMetadata(double.PositiveInfinity, OnXChanged));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double),
typeof(MouseDragElementBehavior), new PropertyMetadata(double.PositiveInfinity, OnYChanged));
// Fields
private Transform _cachedRenderTransform;
private Point _relativePosition;
private bool _settingPosition;
// Properties
public bool ConstrainToParentBounds
{
get =>
(bool) GetValue(ConstrainToParentBoundsProperty);
set => SetValue(ConstrainToParentBoundsProperty, value);
}
private Rect ElementBounds
{
get
{
var layoutRect = ExtendedVisualStateManager.GetLayoutRect(AssociatedObject);
return new Rect(new Point(0.0, 0.0), new Size(layoutRect.Width, layoutRect.Height));
}
}
private FrameworkElement ParentElement =>
AssociatedObject.Parent as FrameworkElement;
private Transform RenderTransform
{
get
{
if (_cachedRenderTransform == null ||
!ReferenceEquals(_cachedRenderTransform, AssociatedObject.RenderTransform))
{
var transform = CloneTransform(AssociatedObject.RenderTransform);
RenderTransform = transform;
}
return _cachedRenderTransform;
}
set
{
if (!Equals(_cachedRenderTransform, value))
{
_cachedRenderTransform = value;
AssociatedObject.RenderTransform = value;
}
}
}
private UIElement RootElement
{
get
{
DependencyObject associatedObject = AssociatedObject;
for (var obj3 = associatedObject; obj3 != null; obj3 = VisualTreeHelper.GetParent(associatedObject))
associatedObject = obj3;
return associatedObject as UIElement;
}
}
public double X
{
get =>
(double) GetValue(XProperty);
set => SetValue(XProperty, value);
}
public double Y
{
get =>
(double) GetValue(YProperty);
set => SetValue(YProperty, value);
}
// Events
public event MouseEventHandler DragBegun;
public event MouseEventHandler DragFinished;
public event MouseEventHandler Dragging;
// Methods
private void ApplyTranslation(double x, double y)
{
if (ParentElement != null)
{
var point = TransformAsVector(RootElement.TransformToVisual(ParentElement), x, y);
x = point.X;
y = point.Y;
if (ConstrainToParentBounds)
{
var parentElement = ParentElement;
var rect = new Rect(0.0, 0.0, parentElement.ActualWidth, parentElement.ActualHeight);
var transform2 = AssociatedObject.TransformToVisual(parentElement);
var elementBounds = ElementBounds;
var rect3 = transform2.TransformBounds(elementBounds);
rect3.X += x;
rect3.Y += y;
if (!RectContainsRect(rect, rect3))
{
if (rect3.X < rect.Left)
{
var num = rect3.X - rect.Left;
x -= num;
}
else if (rect3.Right > rect.Right)
{
var num2 = rect3.Right - rect.Right;
x -= num2;
}
if (rect3.Y < rect.Top)
{
var num3 = rect3.Y - rect.Top;
y -= num3;
}
else if (rect3.Bottom > rect.Bottom)
{
var num4 = rect3.Bottom - rect.Bottom;
y -= num4;
}
}
}
ApplyTranslationTransform(x, y);
}
}
internal void ApplyTranslationTransform(double x, double y)
{
var renderTransform = RenderTransform;
var transform2 = renderTransform as TranslateTransform;
if (transform2 == null)
{
var group = renderTransform as TransformGroup;
var transform3 = renderTransform as MatrixTransform;
if (group != null)
{
if (group.Children.Count > 0)
transform2 = group.Children[group.Children.Count - 1] as TranslateTransform;
if (transform2 == null)
{
transform2 = new TranslateTransform();
group.Children.Add(transform2);
}
}
else
{
if (transform3 != null)
{
var matrix = transform3.Matrix;
matrix.OffsetX += x;
matrix.OffsetY += y;
var transform4 = new MatrixTransform
{
Matrix = matrix
};
RenderTransform = transform4;
return;
}
var group2 = new TransformGroup();
transform2 = new TranslateTransform();
if (renderTransform != null)
group2.Children.Add(renderTransform);
group2.Children.Add(transform2);
RenderTransform = group2;
}
}
transform2.X += x;
transform2.Y += y;
}
internal static Transform CloneTransform(Transform transform)
{
if (transform == null)
return null;
if (transform is ScaleTransform transform2)
return new ScaleTransform
{
CenterX = transform2.CenterX,
CenterY = transform2.CenterY,
ScaleX = transform2.ScaleX,
ScaleY = transform2.ScaleY
};
if (transform is RotateTransform transform3)
return new RotateTransform
{
Angle = transform3.Angle,
CenterX = transform3.CenterX,
CenterY = transform3.CenterY
};
if (transform is SkewTransform transform4)
return new SkewTransform
{
AngleX = transform4.AngleX,
AngleY = transform4.AngleY,
CenterX = transform4.CenterX,
CenterY = transform4.CenterY
};
if (transform is TranslateTransform transform5)
return new TranslateTransform
{
X = transform5.X,
Y = transform5.Y
};
if (transform is MatrixTransform transform6)
return new MatrixTransform {Matrix = transform6.Matrix};
if (!(transform is TransformGroup group))
return null;
var group2 = new TransformGroup();
foreach (var transform12 in group.Children)
group2.Children.Add(CloneTransform(transform12));
return group2;
}
internal void EndDrag()
{
AssociatedObject.MouseMove -= OnMouseMove;
AssociatedObject.LostMouseCapture -= OnLostMouseCapture;
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent,
new MouseButtonEventHandler(OnMouseLeftButtonUp));
}
private static Point GetTransformOffset(GeneralTransform transform)
{
return transform.Transform(new Point(0.0, 0.0));
}
internal void HandleDrag(Point newPositionInElementCoordinates)
{
var x = newPositionInElementCoordinates.X - _relativePosition.X;
var y = newPositionInElementCoordinates.Y - _relativePosition.Y;
var point = TransformAsVector(AssociatedObject.TransformToVisual(RootElement), x, y);
_settingPosition = true;
ApplyTranslation(point.X, point.Y);
UpdatePosition();
_settingPosition = false;
}
protected override void OnAttached()
{
AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnMouseLeftButtonDown), false);
}
private static void OnConstrainToParentBoundsChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var behavior = (MouseDragElementBehavior) sender;
behavior.UpdatePosition(new Point(behavior.X, behavior.Y));
}
protected override void OnDetaching()
{
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnMouseLeftButtonDown));
}
private void OnLostMouseCapture(object sender, MouseEventArgs e)
{
EndDrag();
DragFinished?.Invoke(this, e);
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
StartDrag(e.GetPosition(AssociatedObject));
DragBegun?.Invoke(this, e);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
AssociatedObject.ReleaseMouseCapture();
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
HandleDrag(e.GetPosition(AssociatedObject));
Dragging?.Invoke(this, e);
}
private static void OnXChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var behavior = (MouseDragElementBehavior) sender;
behavior.UpdatePosition(new Point((double) args.NewValue, behavior.Y));
}
private static void OnYChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var behavior = (MouseDragElementBehavior) sender;
behavior.UpdatePosition(new Point(behavior.X, (double) args.NewValue));
}
private static bool RectContainsRect(Rect rect1, Rect rect2)
{
if (rect1.IsEmpty || rect2.IsEmpty)
return false;
return rect1.X <= rect2.X && rect1.Y <= rect2.Y && rect1.X + rect1.Width >= rect2.X + rect2.Width &&
rect1.Y + rect1.Height >= rect2.Y + rect2.Height;
}
internal void StartDrag(Point positionInElementCoordinates)
{
_relativePosition = positionInElementCoordinates;
AssociatedObject.CaptureMouse();
AssociatedObject.MouseMove += OnMouseMove;
AssociatedObject.LostMouseCapture += OnLostMouseCapture;
AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent,
new MouseButtonEventHandler(OnMouseLeftButtonUp), false);
}
private static Point TransformAsVector(GeneralTransform transform, double x, double y)
{
var point = transform.Transform(new Point(0.0, 0.0));
var point2 = transform.Transform(new Point(x, y));
return new Point(point2.X - point.X, point2.Y - point.Y);
}
private void UpdatePosition()
{
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
X = transformOffset.X;
Y = transformOffset.Y;
}
private void UpdatePosition(Point point)
{
if (!_settingPosition && AssociatedObject != null)
{
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
var x = double.IsNaN(point.X) ? 0.0 : point.X - transformOffset.X;
var y = double.IsNaN(point.Y) ? 0.0 : point.Y - transformOffset.Y;
ApplyTranslation(x, y);
}
}
}
}
@@ -0,0 +1,369 @@
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using HandyControl.Data;
using HandyControl.Tools;
namespace HandyControl.Interactivity
{
/// <summary>
/// 鼠标拖动行为,该类是反编译微软的System.Windows.Interactivity程序集得到的,并对其做了些扩展
/// </summary>
internal class MouseDragElementBehaviorEx : Behavior<FrameworkElement>
{
public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double),
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnXChanged));
public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double),
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(double.NaN, OnYChanged));
public static readonly DependencyProperty ConstrainToParentBoundsProperty =
DependencyProperty.Register(nameof(ConstrainToParentBounds), typeof(bool),
typeof(MouseDragElementBehaviorEx), new PropertyMetadata(ValueBoxes.FalseBox, OnConstrainToParentBoundsChanged));
private Transform _cachedRenderTransform;
private Point _relativePosition;
private bool _settingPosition;
/// <summary>
/// 是否固定住Y轴
/// </summary>
public bool LockY { get; set; }
/// <summary>
/// 是否固定住X轴
/// </summary>
public bool LockX { get; set; }
public double X
{
get => (double)GetValue(MouseDragElementBehavior.XProperty);
set => SetValue(MouseDragElementBehavior.XProperty, value);
}
public double Y
{
get => (double)GetValue(MouseDragElementBehavior.YProperty);
set => SetValue(MouseDragElementBehavior.YProperty, value);
}
public bool ConstrainToParentBounds
{
get => (bool)GetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty);
set => SetValue(MouseDragElementBehavior.ConstrainToParentBoundsProperty, value);
}
private Rect ElementBounds
{
get
{
var layoutRect = ArithmeticHelper.GetLayoutRect(AssociatedObject);
return new Rect(new Point(0.0, 0.0), new Size(layoutRect.Width, layoutRect.Height));
}
}
private FrameworkElement ParentElement => AssociatedObject.Parent as FrameworkElement;
private UIElement RootElement
{
get
{
DependencyObject reference = AssociatedObject;
for (var dependencyObject = reference;
dependencyObject != null;
dependencyObject = VisualTreeHelper.GetParent(reference))
reference = dependencyObject;
return reference as UIElement;
}
}
private Transform RenderTransform
{
get
{
if (_cachedRenderTransform == null ||
!ReferenceEquals(_cachedRenderTransform, AssociatedObject.RenderTransform))
RenderTransform = CloneTransform(AssociatedObject.RenderTransform);
return _cachedRenderTransform;
}
set
{
if (Equals(_cachedRenderTransform, value))
return;
_cachedRenderTransform = value;
AssociatedObject.RenderTransform = value;
}
}
public event MouseEventHandler DragBegun;
public event MouseEventHandler Dragging;
public event MouseEventHandler DragFinished;
private static void OnXChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
dragElementBehavior.UpdatePosition(new Point((double)args.NewValue, dragElementBehavior.Y));
}
private static void OnYChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, (double)args.NewValue));
}
private static void OnConstrainToParentBoundsChanged(object sender, DependencyPropertyChangedEventArgs args)
{
var dragElementBehavior = (MouseDragElementBehaviorEx)sender;
dragElementBehavior.UpdatePosition(new Point(dragElementBehavior.X, dragElementBehavior.Y));
}
private void UpdatePosition(Point point)
{
if (_settingPosition || AssociatedObject == null)
return;
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
ApplyTranslation(double.IsNaN(point.X) ? 0.0 : point.X - transformOffset.X,
double.IsNaN(point.Y) ? 0.0 : point.Y - transformOffset.Y);
}
private void ApplyTranslation(double x, double y)
{
if (ParentElement == null)
return;
var point = TransformAsVector(RootElement.TransformToVisual(ParentElement), x, y);
x = point.X;
y = point.Y;
if (ConstrainToParentBounds)
{
var parentElement = ParentElement;
var rect1 = new Rect(0.0, 0.0, parentElement.ActualWidth, parentElement.ActualHeight);
var rect2 = AssociatedObject.TransformToVisual(parentElement).TransformBounds(ElementBounds);
rect2.X += x;
rect2.Y += y;
if (!RectContainsRect(rect1, rect2))
{
if (rect2.X < rect1.Left)
{
var num = rect2.X - rect1.Left;
x -= num;
}
else if (rect2.Right > rect1.Right)
{
var num = rect2.Right - rect1.Right;
x -= num;
}
if (rect2.Y < rect1.Top)
{
var num = rect2.Y - rect1.Top;
y -= num;
}
else if (rect2.Bottom > rect1.Bottom)
{
var num = rect2.Bottom - rect1.Bottom;
y -= num;
}
}
}
ApplyTranslationTransform(x, y);
}
internal void ApplyTranslationTransform(double x, double y)
{
var renderTransform = RenderTransform;
var translateTransform = renderTransform as TranslateTransform;
if (translateTransform == null)
{
var matrixTransform = renderTransform as MatrixTransform;
if (renderTransform is TransformGroup transformGroup1)
{
if (transformGroup1.Children.Count > 0)
translateTransform =
transformGroup1.Children[transformGroup1.Children.Count - 1] as TranslateTransform;
if (translateTransform == null)
{
translateTransform = new TranslateTransform();
transformGroup1.Children.Add(translateTransform);
}
}
else
{
if (matrixTransform != null)
{
var matrix = matrixTransform.Matrix;
//在该处对微软的类进行了修改
if (!LockX)
{
matrix.OffsetX += x;
}
if (!LockY)
{
matrix.OffsetY += y;
}
//修改结束
RenderTransform = new MatrixTransform
{
Matrix = matrix
};
return;
}
var transformGroup2 = new TransformGroup();
translateTransform = new TranslateTransform();
if (renderTransform != null)
transformGroup2.Children.Add(renderTransform);
transformGroup2.Children.Add(translateTransform);
RenderTransform = transformGroup2;
}
}
//在该处对微软的类进行了修改
if (!LockX)
{
translateTransform.X += x;
}
if (!LockY)
{
translateTransform.Y += y;
}
//修改结束
}
internal static Transform CloneTransform(Transform transform)
{
if (transform == null)
return null;
if (transform is ScaleTransform scaleTransform)
return new ScaleTransform
{
CenterX = scaleTransform.CenterX,
CenterY = scaleTransform.CenterY,
ScaleX = scaleTransform.ScaleX,
ScaleY = scaleTransform.ScaleY
};
if (transform is RotateTransform rotateTransform)
return new RotateTransform
{
Angle = rotateTransform.Angle,
CenterX = rotateTransform.CenterX,
CenterY = rotateTransform.CenterY
};
if (transform is SkewTransform skewTransform)
return new SkewTransform
{
AngleX = skewTransform.AngleX,
AngleY = skewTransform.AngleY,
CenterX = skewTransform.CenterX,
CenterY = skewTransform.CenterY
};
if (transform is TranslateTransform translateTransform)
return new TranslateTransform
{
X = translateTransform.X,
Y = translateTransform.Y
};
if (transform is MatrixTransform matrixTransform)
return new MatrixTransform
{
Matrix = matrixTransform.Matrix
};
if (!(transform is TransformGroup transformGroup1))
return null;
var transformGroup2 = new TransformGroup();
foreach (var child in transformGroup1.Children)
transformGroup2.Children.Add(CloneTransform(child));
return transformGroup2;
}
private void UpdatePosition()
{
var transformOffset = GetTransformOffset(AssociatedObject.TransformToVisual(RootElement));
X = transformOffset.X;
Y = transformOffset.Y;
}
internal void StartDrag(Point positionInElementCoordinates)
{
_relativePosition = positionInElementCoordinates;
AssociatedObject.CaptureMouse();
AssociatedObject.MouseMove += OnMouseMove;
AssociatedObject.LostMouseCapture += OnLostMouseCapture;
AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent,
new MouseButtonEventHandler(OnMouseLeftButtonUp), false);
}
internal void HandleDrag(Point newPositionInElementCoordinates)
{
var point = TransformAsVector(AssociatedObject.TransformToVisual(RootElement),
newPositionInElementCoordinates.X - _relativePosition.X,
newPositionInElementCoordinates.Y - _relativePosition.Y);
_settingPosition = true;
ApplyTranslation(point.X, point.Y);
UpdatePosition();
_settingPosition = false;
}
internal void EndDrag()
{
AssociatedObject.MouseMove -= OnMouseMove;
AssociatedObject.LostMouseCapture -= OnLostMouseCapture;
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonUpEvent,
new MouseButtonEventHandler(OnMouseLeftButtonUp));
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
StartDrag(e.GetPosition(AssociatedObject));
DragBegun?.Invoke(this, e);
}
private void OnLostMouseCapture(object sender, MouseEventArgs e)
{
EndDrag();
DragFinished?.Invoke(this, e);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
AssociatedObject.ReleaseMouseCapture();
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
HandleDrag(e.GetPosition(AssociatedObject));
Dragging?.Invoke(this, e);
}
private static bool RectContainsRect(Rect rect1, Rect rect2)
{
if (rect1.IsEmpty || rect2.IsEmpty || rect1.X > rect2.X || rect1.Y > rect2.Y ||
rect1.X + rect1.Width < rect2.X + rect2.Width)
return false;
return rect1.Y + rect1.Height >= rect2.Y + rect2.Height;
}
private static Point TransformAsVector(GeneralTransform transform, double x, double y)
{
var point1 = transform.Transform(new Point(0.0, 0.0));
var point2 = transform.Transform(new Point(x, y));
return new Point(point2.X - point1.X, point2.Y - point1.Y);
}
private static Point GetTransformOffset(GeneralTransform transform)
{
return transform.Transform(new Point(0.0, 0.0));
}
protected override void OnAttached()
{
AssociatedObject.AddHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnMouseLeftButtonDown), false);
}
protected override void OnDetaching()
{
AssociatedObject.RemoveHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(OnMouseLeftButtonDown));
}
}
}