support for .NET framework 3.5

Still have bugs
This commit is contained in:
NaBian committed 2019-01-21 00:43:10 +08:00
1 parent 5878039e21
commit 7d6b491f25
704 files changed
+48273 -33

No files matched your search

@@ -0,0 +1,40 @@
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace HandyControl.Interactivity
{
public class AdornerContainer : Adorner
{
private UIElement _child;
public AdornerContainer(UIElement adornedElement) : base(adornedElement)
{
}
public UIElement Child
{
get =>
_child;
set
{
AddVisualChild(value);
_child = value;
}
}
protected override int VisualChildrenCount => _child != null ? 1 : 0;
protected override Size ArrangeOverride(Size finalSize)
{
_child?.Arrange(new Rect(finalSize));
return finalSize;
}
protected override Visual GetVisualChild(int index)
{
if (index == 0 && _child != null) return _child;
return base.GetVisualChild(index);
}
}
}
@@ -0,0 +1,168 @@
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
namespace HandyControl.Interactivity
{
public abstract class AttachableCollection<T> : FreezableCollection<T>, IAttachedObject
where T : DependencyObject, IAttachedObject
{
private DependencyObject _associatedObject;
private Collection<T> _snapshot;
internal AttachableCollection()
{
INotifyCollectionChanged changed = this;
changed.CollectionChanged += OnCollectionChanged;
_snapshot = new Collection<T>();
}
public DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
DependencyObject IAttachedObject.AssociatedObject => AssociatedObject;
public void Attach(DependencyObject dependencyObject)
{
if (Equals(dependencyObject, AssociatedObject))
return;
if (AssociatedObject != null)
throw new InvalidOperationException();
if (Interaction.ShouldRunInDesignMode || !(bool) GetValue(DesignerProperties.IsInDesignModeProperty))
{
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
}
OnAttached();
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
}
protected abstract void OnAttached();
protected abstract void OnDetaching();
internal abstract void ItemAdded(T item);
internal abstract void ItemRemoved(T item);
private void VerifyAdd(T item)
{
if (item == null) throw new ArgumentNullException(nameof(item));
if (_snapshot.Contains(item))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.DuplicateItemInCollectionExceptionMessage, new object[]
{
typeof(T).Name,
GetType().Name
}));
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
var enumerator1 = e.NewItems.GetEnumerator();
try
{
while (enumerator1.MoveNext())
{
var current = (T) enumerator1.Current;
try
{
VerifyAdd(current);
ItemAdded(current);
}
finally
{
_snapshot.Insert(IndexOf(current), current);
}
}
break;
}
finally
{
if (enumerator1 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Remove:
var enumerator2 = e.OldItems.GetEnumerator();
try
{
while (enumerator2.MoveNext())
{
var current = (T) enumerator2.Current;
ItemRemoved(current);
_snapshot.Remove(current);
}
break;
}
finally
{
if (enumerator2 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Replace:
foreach (T oldItem in e.OldItems)
{
ItemRemoved(oldItem);
_snapshot.Remove(oldItem);
}
var enumerator3 = e.NewItems.GetEnumerator();
try
{
while (enumerator3.MoveNext())
{
var current = (T) enumerator3.Current;
try
{
VerifyAdd(current);
ItemAdded(current);
}
finally
{
_snapshot.Insert(IndexOf(current), current);
}
}
break;
}
finally
{
if (enumerator3 is IDisposable disposable)
disposable.Dispose();
}
case NotifyCollectionChangedAction.Reset:
foreach (var obj in _snapshot)
ItemRemoved(obj);
_snapshot = new Collection<T>();
using (var enumerator4 = GetEnumerator())
{
while (enumerator4.MoveNext())
{
var current = enumerator4.Current;
VerifyAdd(current);
ItemAdded(current);
}
break;
}
}
}
}
}
@@ -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 (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,150 @@
using System.Windows.Input;
namespace HandyControl.Interactivity
{
/// <summary>
/// 控件库使用的所有命令(为了统一,不使用wpf自带的命令)
/// </summary>
public static class ControlCommands
{
/// <summary>
/// 搜索
/// </summary>
public static RoutedCommand Search { get; } = new RoutedCommand(nameof(Search), typeof(ControlCommands));
/// <summary>
/// 清除
/// </summary>
public static RoutedCommand Clear { get; } = new RoutedCommand(nameof(Clear), typeof(ControlCommands));
/// <summary>
/// 切换
/// </summary>
public static RoutedCommand Switch { get; } = new RoutedCommand(nameof(Switch), typeof(ControlCommands));
/// <summary>
/// 右转
/// </summary>
public static RoutedCommand RotateRight { get; } = new RoutedCommand(nameof(RotateRight), typeof(ControlCommands));
/// <summary>
/// 左转
/// </summary>
public static RoutedCommand RotateLeft { get; } = new RoutedCommand(nameof(RotateLeft), typeof(ControlCommands));
/// <summary>
/// 小
/// </summary>
public static RoutedCommand Reduce { get; } = new RoutedCommand(nameof(Reduce), typeof(ControlCommands));
/// <summary>
/// 大
/// </summary>
public static RoutedCommand Enlarge { get; } = new RoutedCommand(nameof(Enlarge), typeof(ControlCommands));
/// <summary>
/// 还原
/// </summary>
public static RoutedCommand Restore { get; } = new RoutedCommand(nameof(Restore), typeof(ControlCommands));
/// <summary>
/// 打开
/// </summary>
public static RoutedCommand Open { get; } = new RoutedCommand(nameof(Open), typeof(ControlCommands));
/// <summary>
/// 保存
/// </summary>
public static RoutedCommand Save { get; } = new RoutedCommand(nameof(Save), typeof(ControlCommands));
/// <summary>
/// 选中
/// </summary>
public static RoutedCommand Selected { get; } = new RoutedCommand(nameof(Selected), typeof(ControlCommands));
/// <summary>
/// 关闭
/// </summary>
public static RoutedCommand Close { get; } = new RoutedCommand(nameof(Close), typeof(ControlCommands));
/// <summary>
/// 取消
/// </summary>
public static RoutedCommand Cancel { get; } = new RoutedCommand(nameof(Cancel), typeof(ControlCommands));
/// <summary>
/// 确定
/// </summary>
public static RoutedCommand Confirm { get; } = new RoutedCommand(nameof(Confirm), typeof(ControlCommands));
/// <summary>
/// 是
/// </summary>
public static RoutedCommand Yes { get; } = new RoutedCommand(nameof(Yes), typeof(ControlCommands));
/// <summary>
/// 否
/// </summary>
public static RoutedCommand No { get; } = new RoutedCommand(nameof(No), typeof(ControlCommands));
/// <summary>
/// 关闭所有
/// </summary>
public static RoutedCommand CloseAll { get; } = new RoutedCommand(nameof(CloseAll), typeof(ControlCommands));
/// <summary>
/// 关闭其他
/// </summary>
public static RoutedCommand CloseOther { get; } = new RoutedCommand(nameof(CloseOther), typeof(ControlCommands));
/// <summary>
/// 上一个
/// </summary>
public static RoutedCommand Prev { get; } = new RoutedCommand(nameof(Prev), typeof(ControlCommands));
/// <summary>
/// 下一个
/// </summary>
public static RoutedCommand Next { get; } = new RoutedCommand(nameof(Next), typeof(ControlCommands));
/// <summary>
/// 上午
/// </summary>
public static RoutedCommand Am { get; } = new RoutedCommand(nameof(Am), typeof(ControlCommands));
/// <summary>
/// 下午
/// </summary>
public static RoutedCommand Pm { get; } = new RoutedCommand(nameof(Pm), typeof(ControlCommands));
/// <summary>
/// 确认
/// </summary>
public static RoutedCommand Sure { get; } = new RoutedCommand(nameof(Sure), typeof(ControlCommands));
/// <summary>
/// 小时改变
/// </summary>
public static RoutedCommand HourChange { get; } = new RoutedCommand(nameof(HourChange), typeof(ControlCommands));
/// <summary>
/// 分钟改变
/// </summary>
public static RoutedCommand MinuteChange { get; } = new RoutedCommand(nameof(MinuteChange), typeof(ControlCommands));
/// <summary>
/// 秒改变
/// </summary>
public static RoutedCommand SecondChange { get; } = new RoutedCommand(nameof(SecondChange), typeof(ControlCommands));
/// <summary>
/// 鼠标移动
/// </summary>
public static RoutedCommand MouseMove { get; } = new RoutedCommand(nameof(MouseMove), typeof(ControlCommands));
/// <summary>
/// 打开链接
/// </summary>
public static RoutedCommand OpenLink { get; } = new RoutedCommand(nameof(OpenLink), typeof(ControlCommands));
}
}
@@ -0,0 +1,49 @@
using System;
using System.Collections;
using System.Globalization;
namespace HandyControl.Interactivity
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Class, AllowMultiple = true)]
public sealed class DefaultTriggerAttribute : Attribute
{
private readonly object[] _parameters;
public DefaultTriggerAttribute(Type targetType, Type triggerType, object parameter) : this(targetType,
triggerType, new[] {parameter})
{
}
public DefaultTriggerAttribute(Type targetType, Type triggerType, params object[] parameters)
{
if (!typeof(TriggerBase).IsAssignableFrom(triggerType))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.DefaultTriggerAttributeInvalidTriggerTypeSpecifiedExceptionMessage,
new object[] {triggerType.Name}));
TargetType = targetType;
TriggerType = triggerType;
_parameters = parameters;
}
public IEnumerable Parameters =>
_parameters;
public Type TargetType { get; }
public Type TriggerType { get; }
public TriggerBase Instantiate()
{
object obj2 = null;
try
{
obj2 = Activator.CreateInstance(TriggerType, _parameters);
}
catch
{
// ignored
}
return (TriggerBase) obj2;
}
}
}
@@ -0,0 +1,195 @@
/*refrence from https://github.com/lbugnion/mvvmlight*/
//The MIT License(MIT)
//Copyright(c) 2009 - 2018 Laurent Bugnion
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
using System;
using System.Windows;
using System.Windows.Input;
using HandyControl.Data;
namespace HandyControl.Interactivity
{
public class EventToCommand : TriggerAction<DependencyObject>
{
public const string EventArgsConverterParameterPropertyName = "EventArgsConverterParameter";
public const string AlwaysInvokeCommandPropertyName = "AlwaysInvokeCommand";
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
nameof(CommandParameter), typeof(object), typeof(EventToCommand), new PropertyMetadata(null,
(s, e) =>
{
var eventToCommand = s as EventToCommand;
if (eventToCommand?.AssociatedObject == null)
return;
eventToCommand.EnableDisableElement();
}));
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(EventToCommand),
new PropertyMetadata(null, (s, e) => OnCommandChanged(s as EventToCommand, e)));
public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register(
nameof(MustToggleIsEnabled), typeof(bool), typeof(EventToCommand), new PropertyMetadata(ValueBoxes.FalseBox,
(s, e) =>
{
var eventToCommand = s as EventToCommand;
if (eventToCommand?.AssociatedObject == null)
return;
eventToCommand.EnableDisableElement();
}));
public static readonly DependencyProperty EventArgsConverterParameterProperty =
DependencyProperty.Register(nameof(EventArgsConverterParameter), typeof(object),
typeof(EventToCommand), new PropertyMetadata(null));
public static readonly DependencyProperty AlwaysInvokeCommandProperty =
DependencyProperty.Register(nameof(AlwaysInvokeCommand), typeof(bool), typeof(EventToCommand),
new PropertyMetadata(ValueBoxes.FalseBox));
private object _commandParameterValue;
private bool? _mustToggleValue;
public ICommand Command
{
get => (ICommand) GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public object CommandParameterValue
{
get => _commandParameterValue ?? CommandParameter;
set
{
_commandParameterValue = value;
EnableDisableElement();
}
}
public bool MustToggleIsEnabled
{
get => (bool) GetValue(MustToggleIsEnabledProperty);
set => SetValue(MustToggleIsEnabledProperty, value);
}
public bool MustToggleIsEnabledValue
{
get
{
if (_mustToggleValue.HasValue)
return _mustToggleValue.Value;
return MustToggleIsEnabled;
}
set
{
_mustToggleValue = value;
EnableDisableElement();
}
}
public bool PassEventArgsToCommand { get; set; }
public IEventArgsConverter EventArgsConverter { get; set; }
public object EventArgsConverterParameter
{
get => GetValue(EventArgsConverterParameterProperty);
set => SetValue(EventArgsConverterParameterProperty, value);
}
public bool AlwaysInvokeCommand
{
get => (bool) GetValue(AlwaysInvokeCommandProperty);
set => SetValue(AlwaysInvokeCommandProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
EnableDisableElement();
}
private FrameworkElement GetAssociatedObject() => AssociatedObject as FrameworkElement;
private ICommand GetCommand() => Command;
public void Invoke() => Invoke(null);
protected override void Invoke(object parameter)
{
if (AssociatedElementIsDisabled() && !AlwaysInvokeCommand)
return;
var command = GetCommand();
var parameter1 = CommandParameterValue;
if (parameter1 == null && PassEventArgsToCommand)
parameter1 = EventArgsConverter == null
? parameter
: EventArgsConverter.Convert(parameter, EventArgsConverterParameter);
if (command == null || !command.CanExecute(parameter1))
return;
command.Execute(parameter1);
}
private static void OnCommandChanged(EventToCommand element, DependencyPropertyChangedEventArgs e)
{
if (element == null)
return;
if (e.OldValue != null)
((ICommand) e.OldValue).CanExecuteChanged -= element.OnCommandCanExecuteChanged;
var newValue = (ICommand) e.NewValue;
if (newValue != null)
newValue.CanExecuteChanged += element.OnCommandCanExecuteChanged;
element.EnableDisableElement();
}
private bool AssociatedElementIsDisabled()
{
var associatedObject = GetAssociatedObject();
if (AssociatedObject == null)
return true;
if (associatedObject != null)
return !associatedObject.IsEnabled;
return false;
}
private void EnableDisableElement()
{
var associatedObject = GetAssociatedObject();
if (associatedObject == null)
return;
var command = GetCommand();
if (!MustToggleIsEnabledValue || command == null)
return;
associatedObject.IsEnabled = command.CanExecute(CommandParameterValue);
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e) => EnableDisableElement();
}
}
@@ -0,0 +1,29 @@
using System.Windows;
namespace HandyControl.Interactivity
{
public class EventTrigger : EventTriggerBase<object>
{
public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(EventTrigger), new FrameworkPropertyMetadata("Loaded", OnEventNameChanged));
public EventTrigger()
{
}
public EventTrigger(string eventName) => EventName = eventName;
protected override string GetEventName() => EventName;
private static void OnEventNameChanged(object sender, DependencyPropertyChangedEventArgs args)
{
((EventTrigger)sender).OnEventNameChanged((string)args.OldValue, (string)args.NewValue);
}
public string EventName
{
get => (string)GetValue(EventNameProperty);
set => SetValue(EventNameProperty, value);
}
}
}
@@ -0,0 +1,21 @@
namespace HandyControl.Interactivity
{
public abstract class EventTriggerBase<T> : EventTriggerBase where T : class
{
protected EventTriggerBase() : base(typeof(T))
{
}
protected virtual void OnSourceChanged(T oldSource, T newSource)
{
}
internal sealed override void OnSourceChangedImpl(object oldSource, object newSource)
{
base.OnSourceChangedImpl(oldSource, newSource);
OnSourceChanged(oldSource as T, newSource as T);
}
public new T Source => (T)base.Source;
}
}
@@ -0,0 +1,313 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;
namespace HandyControl.Interactivity
{
public abstract class EventTriggerBase : TriggerBase
{
public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register("SourceName",
typeof(string), typeof(EventTriggerBase), new PropertyMetadata(OnSourceNameChanged));
public static readonly DependencyProperty SourceObjectProperty = DependencyProperty.Register("SourceObject",
typeof(object), typeof(EventTriggerBase), new PropertyMetadata(OnSourceObjectChanged));
private MethodInfo _eventHandlerMethodInfo;
internal EventTriggerBase(Type sourceTypeConstraint) : base(typeof(DependencyObject))
{
SourceTypeConstraint = sourceTypeConstraint;
SourceNameResolver = new NameResolver();
RegisterSourceChanged();
}
protected sealed override Type AssociatedObjectTypeConstraint
{
get
{
if (TypeDescriptor.GetAttributes(GetType())[typeof(TypeConstraintAttribute)] is TypeConstraintAttribute attribute)
return attribute.Constraint;
return typeof(DependencyObject);
}
}
private bool IsLoadedRegistered { get; set; }
private bool IsSourceChangedRegistered { get; set; }
private bool IsSourceNameSet
{
get
{
if (string.IsNullOrEmpty(SourceName))
return ReadLocalValue(SourceNameProperty) != DependencyProperty.UnsetValue;
return true;
}
}
public object Source
{
get
{
object associatedObject = AssociatedObject;
if (SourceObject != null)
return SourceObject;
if (IsSourceNameSet)
{
associatedObject = SourceNameResolver.Object;
if (associatedObject != null && !SourceTypeConstraint.IsInstanceOfType(associatedObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.RetargetedTypeConstraintViolatedExceptionMessage, GetType().Name,
associatedObject.GetType(), SourceTypeConstraint, "Source"));
}
return associatedObject;
}
}
public string SourceName
{
get =>
(string) GetValue(SourceNameProperty);
set => SetValue(SourceNameProperty, value);
}
private NameResolver SourceNameResolver { get; }
public object SourceObject
{
get =>
GetValue(SourceObjectProperty);
set => SetValue(SourceObjectProperty, value);
}
protected Type SourceTypeConstraint { get; }
protected abstract string GetEventName();
private static bool IsValidEvent(EventInfo eventInfo)
{
var eventHandlerType = eventInfo.EventHandlerType;
if (!typeof(Delegate).IsAssignableFrom(eventInfo.EventHandlerType))
return false;
var parameters = eventHandlerType.GetMethod("Invoke")?.GetParameters();
return parameters != null && parameters.Length == 2 && typeof(object).IsAssignableFrom(parameters[0].ParameterType) && typeof(EventArgs).IsAssignableFrom(parameters[1].ParameterType);
}
protected override void OnAttached()
{
base.OnAttached();
var associatedObject = AssociatedObject;
var behavior = associatedObject as Behavior;
var element = associatedObject as FrameworkElement;
RegisterSourceChanged();
if (behavior != null)
{
behavior.AssociatedObjectChanged += OnBehaviorHostChanged;
}
else if (SourceObject != null || element == null)
{
try
{
OnSourceChanged(null, Source);
}
catch (InvalidOperationException)
{
}
}
else
{
SourceNameResolver.NameScopeReferenceElement = element;
}
if (string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) == 0 && element != null &&
!Interaction.IsElementLoaded(element))
RegisterLoaded(element);
}
private void OnBehaviorHostChanged(object sender, EventArgs e)
{
SourceNameResolver.NameScopeReferenceElement =
((IAttachedObject) sender).AssociatedObject as FrameworkElement;
}
protected override void OnDetaching()
{
base.OnDetaching();
var associatedObject = AssociatedObject as Behavior;
var associatedElement = AssociatedObject as FrameworkElement;
try
{
OnSourceChanged(Source, null);
}
catch (InvalidOperationException)
{
}
UnregisterSourceChanged();
if (associatedObject != null)
associatedObject.AssociatedObjectChanged -= OnBehaviorHostChanged;
SourceNameResolver.NameScopeReferenceElement = null;
if (string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) == 0 && associatedElement != null)
UnregisterLoaded(associatedElement);
}
protected virtual void OnEvent(EventArgs eventArgs)
{
InvokeActions(eventArgs);
}
private void OnEventImpl(object sender, EventArgs eventArgs)
{
OnEvent(eventArgs);
}
internal void OnEventNameChanged(string oldEventName, string newEventName)
{
if (AssociatedObject != null)
{
var source = Source as FrameworkElement;
if (source != null && string.Compare(oldEventName, "Loaded", StringComparison.Ordinal) == 0)
UnregisterLoaded(source);
else if (!string.IsNullOrEmpty(oldEventName))
UnregisterEvent(Source, oldEventName);
if (source != null && string.Compare(newEventName, "Loaded", StringComparison.Ordinal) == 0)
RegisterLoaded(source);
else if (!string.IsNullOrEmpty(newEventName))
RegisterEvent(Source, newEventName);
}
}
private void OnSourceChanged(object oldSource, object newSource)
{
if (AssociatedObject != null)
OnSourceChangedImpl(oldSource, newSource);
}
internal virtual void OnSourceChangedImpl(object oldSource, object newSource)
{
if (!string.IsNullOrEmpty(GetEventName()) &&
string.Compare(GetEventName(), "Loaded", StringComparison.Ordinal) != 0)
{
if (oldSource != null && SourceTypeConstraint.IsInstanceOfType(oldSource))
UnregisterEvent(oldSource, GetEventName());
if (newSource != null && SourceTypeConstraint.IsInstanceOfType(newSource))
RegisterEvent(newSource, GetEventName());
}
}
private static void OnSourceNameChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var base2 = (EventTriggerBase) obj;
base2.SourceNameResolver.Name = (string) args.NewValue;
}
private void OnSourceNameResolverElementChanged(object sender, NameResolvedEventArgs e)
{
if (SourceObject == null)
OnSourceChanged(e.OldObject, e.NewObject);
}
private static void OnSourceObjectChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var base2 = (EventTriggerBase) obj;
object newSource = base2.SourceNameResolver.Object;
if (args.NewValue == null)
{
base2.OnSourceChanged(args.OldValue, newSource);
}
else
{
if (args.OldValue == null && newSource != null)
base2.UnregisterEvent(newSource, base2.GetEventName());
base2.OnSourceChanged(args.OldValue, args.NewValue);
}
}
private void RegisterEvent(object obj, string eventName)
{
var eventInfo = obj.GetType().GetEvent(eventName);
if (eventInfo == null)
{
if (SourceObject != null)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.EventTriggerCannotFindEventNameExceptionMessage,
new object[] {eventName, obj.GetType().Name}));
}
else if (!IsValidEvent(eventInfo))
{
if (SourceObject != null)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.EventTriggerBaseInvalidEventExceptionMessage,
new object[] {eventName, obj.GetType().Name}));
}
else
{
_eventHandlerMethodInfo =
typeof(EventTriggerBase).GetMethod("OnEventImpl", BindingFlags.NonPublic | BindingFlags.Instance);
eventInfo.AddEventHandler(obj,
Delegate.CreateDelegate(eventInfo.EventHandlerType, this, _eventHandlerMethodInfo ?? throw new InvalidOperationException()));
}
}
private void RegisterLoaded(FrameworkElement associatedElement)
{
if (!IsLoadedRegistered && associatedElement != null)
{
associatedElement.Loaded += OnEventImpl;
IsLoadedRegistered = true;
}
}
private void RegisterSourceChanged()
{
if (!IsSourceChangedRegistered)
{
SourceNameResolver.ResolvedElementChanged += OnSourceNameResolverElementChanged;
IsSourceChangedRegistered = true;
}
}
private void UnregisterEvent(object obj, string eventName)
{
if (string.Compare(eventName, "Loaded", StringComparison.Ordinal) == 0)
{
if (obj is FrameworkElement associatedElement)
UnregisterLoaded(associatedElement);
}
else
{
UnregisterEventImpl(obj, eventName);
}
}
private void UnregisterEventImpl(object obj, string eventName)
{
var type = obj.GetType();
if (_eventHandlerMethodInfo != null)
{
var info = type.GetEvent(eventName);
info.RemoveEventHandler(obj,
Delegate.CreateDelegate(info.EventHandlerType, this, _eventHandlerMethodInfo));
_eventHandlerMethodInfo = null;
}
}
private void UnregisterLoaded(FrameworkElement associatedElement)
{
if (IsLoadedRegistered && associatedElement != null)
{
associatedElement.Loaded -= OnEventImpl;
IsLoadedRegistered = false;
}
}
private void UnregisterSourceChanged()
{
if (IsSourceChangedRegistered)
{
SourceNameResolver.ResolvedElementChanged -= OnSourceNameResolverElementChanged;
IsSourceChangedRegistered = false;
}
}
}
}
@@ -0,0 +1,58 @@
using System.ComponentModel;
using System.Globalization;
using System.Resources;
namespace HandyControl.Interactivity
{
internal class ExceptionStringTable
{
private static ResourceManager ResourceMan;
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager => ResourceMan ?? (ResourceMan = new ResourceManager(nameof(ExceptionStringTable),
typeof(ExceptionStringTable).Assembly));
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static CultureInfo Culture { get; set; }
internal static string CannotHostBehaviorCollectionMultipleTimesExceptionMessage =>
ResourceManager.GetString(nameof(CannotHostBehaviorCollectionMultipleTimesExceptionMessage), Culture);
internal static string CannotHostBehaviorMultipleTimesExceptionMessage =>
ResourceManager.GetString(nameof(CannotHostBehaviorMultipleTimesExceptionMessage), Culture);
internal static string CannotHostTriggerActionMultipleTimesExceptionMessage =>
ResourceManager.GetString(nameof(CannotHostTriggerActionMultipleTimesExceptionMessage), Culture);
internal static string CannotHostTriggerCollectionMultipleTimesExceptionMessage =>
ResourceManager.GetString(nameof(CannotHostTriggerCollectionMultipleTimesExceptionMessage), Culture);
internal static string CannotHostTriggerMultipleTimesExceptionMessage =>
ResourceManager.GetString(nameof(CannotHostTriggerMultipleTimesExceptionMessage), Culture);
internal static string CommandDoesNotExistOnBehaviorWarningMessage =>
ResourceManager.GetString(nameof(CommandDoesNotExistOnBehaviorWarningMessage), Culture);
internal static string DefaultTriggerAttributeInvalidTriggerTypeSpecifiedExceptionMessage =>
ResourceManager.GetString(nameof(DefaultTriggerAttributeInvalidTriggerTypeSpecifiedExceptionMessage),
Culture);
internal static string DuplicateItemInCollectionExceptionMessage =>
ResourceManager.GetString(nameof(DuplicateItemInCollectionExceptionMessage), Culture);
internal static string EventTriggerBaseInvalidEventExceptionMessage =>
ResourceManager.GetString(nameof(EventTriggerBaseInvalidEventExceptionMessage), Culture);
internal static string EventTriggerCannotFindEventNameExceptionMessage =>
ResourceManager.GetString(nameof(EventTriggerCannotFindEventNameExceptionMessage), Culture);
internal static string RetargetedTypeConstraintViolatedExceptionMessage =>
ResourceManager.GetString(nameof(RetargetedTypeConstraintViolatedExceptionMessage), Culture);
internal static string TypeConstraintViolatedExceptionMessage =>
ResourceManager.GetString(nameof(TypeConstraintViolatedExceptionMessage), Culture);
internal static string UnableToResolveTargetNameWarningMessage =>
ResourceManager.GetString(nameof(UnableToResolveTargetNameWarningMessage), Culture);
}
}
@@ -0,0 +1,71 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace HandyControl.Interactivity
{
public class ExtendedVisualStateManager
{
internal static Rect GetLayoutRect(FrameworkElement element)
{
var actualWidth = element.ActualWidth;
var actualHeight = element.ActualHeight;
if (element is Image || element is MediaElement)
if (element.Parent is Canvas)
{
actualWidth = double.IsNaN(element.Width) ? actualWidth : element.Width;
actualHeight = double.IsNaN(element.Height) ? actualHeight : element.Height;
}
else
{
actualWidth = element.RenderSize.Width;
actualHeight = element.RenderSize.Height;
}
actualWidth = element.Visibility == Visibility.Collapsed ? 0.0 : actualWidth;
actualHeight = element.Visibility == Visibility.Collapsed ? 0.0 : actualHeight;
var margin = element.Margin;
var layoutSlot = LayoutInformation.GetLayoutSlot(element);
var x = 0.0;
var y = 0.0;
switch (element.HorizontalAlignment)
{
case HorizontalAlignment.Left:
x = layoutSlot.Left + margin.Left;
break;
case HorizontalAlignment.Center:
x = (layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - actualWidth / 2.0;
break;
case HorizontalAlignment.Right:
x = layoutSlot.Right - margin.Right - actualWidth;
break;
case HorizontalAlignment.Stretch:
x = Math.Max(layoutSlot.Left + margin.Left,
(layoutSlot.Left + margin.Left + layoutSlot.Right - margin.Right) / 2.0 - actualWidth / 2.0);
break;
}
switch (element.VerticalAlignment)
{
case VerticalAlignment.Top:
y = layoutSlot.Top + margin.Top;
break;
case VerticalAlignment.Center:
y = (layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - actualHeight / 2.0;
break;
case VerticalAlignment.Bottom:
y = layoutSlot.Bottom - margin.Bottom - actualHeight;
break;
case VerticalAlignment.Stretch:
y = Math.Max(layoutSlot.Top + margin.Top,
(layoutSlot.Top + margin.Top + layoutSlot.Bottom - margin.Bottom) / 2.0 - actualHeight / 2.0);
break;
}
return new Rect(x, y, actualWidth, actualHeight);
}
}
}
@@ -0,0 +1,425 @@
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 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 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)"));
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)"));
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)"));
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)"));
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,8 @@
namespace HandyControl.Interactivity
{
public enum FluidMoveScope
{
Self,
Children
}
}
@@ -0,0 +1,12 @@
using System.Windows;
namespace HandyControl.Interactivity
{
public interface IAttachedObject
{
void Attach(DependencyObject dependencyObject);
void Detach();
DependencyObject AssociatedObject { get; }
}
}
@@ -0,0 +1,31 @@
/*refrence from https://github.com/lbugnion/mvvmlight*/
//The MIT License(MIT)
//Copyright(c) 2009 - 2018 Laurent Bugnion
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
namespace HandyControl.Interactivity
{
public interface IEventArgsConverter
{
object Convert(object value, object parameter);
}
}
@@ -0,0 +1,77 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity
{
public static class Interaction
{
private static readonly DependencyProperty TriggersProperty =
DependencyProperty.RegisterAttached("ShadowTriggers", typeof(TriggerCollection), typeof(Interaction),
new FrameworkPropertyMetadata(OnTriggersChanged));
private static readonly DependencyProperty BehaviorsProperty =
DependencyProperty.RegisterAttached("ShadowBehaviors", typeof(BehaviorCollection), typeof(Interaction),
new FrameworkPropertyMetadata(OnBehaviorsChanged));
internal static bool ShouldRunInDesignMode { get; set; }
public static TriggerCollection GetTriggers(DependencyObject obj)
{
var triggerCollection = (TriggerCollection) obj.GetValue(TriggersProperty);
if (triggerCollection == null)
{
triggerCollection = new TriggerCollection();
obj.SetValue(TriggersProperty, triggerCollection);
}
return triggerCollection;
}
public static BehaviorCollection GetBehaviors(DependencyObject obj)
{
var behaviorCollection = (BehaviorCollection) obj.GetValue(BehaviorsProperty);
if (behaviorCollection == null)
{
behaviorCollection = new BehaviorCollection();
obj.SetValue(BehaviorsProperty, behaviorCollection);
}
return behaviorCollection;
}
private static void OnBehaviorsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = (BehaviorCollection) args.OldValue;
var newValue = (BehaviorCollection) args.NewValue;
if (Equals(oldValue, newValue))
return;
if (oldValue?.AssociatedObject != null)
oldValue.Detach();
if (newValue == null || obj == null)
return;
if (newValue.AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostBehaviorCollectionMultipleTimesExceptionMessage);
newValue.Attach(obj);
}
private static void OnTriggersChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var oldValue = args.OldValue as TriggerCollection;
var newValue = args.NewValue as TriggerCollection;
if (Equals(oldValue, newValue))
return;
if (oldValue?.AssociatedObject != null)
oldValue.Detach();
if (newValue == null || obj == null)
return;
if (newValue.AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerCollectionMultipleTimesExceptionMessage);
newValue.Attach(obj);
}
internal static bool IsElementLoaded(FrameworkElement element)
{
return element.IsLoaded;
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
namespace HandyControl.Interactivity
{
public sealed class InvokeCommandAction : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(InvokeCommandAction), null);
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(InvokeCommandAction),
null);
private string _commandName;
public string CommandName
{
get
{
ReadPreamble();
return _commandName;
}
set
{
if (CommandName == value)
return;
WritePreamble();
_commandName = value;
WritePostscript();
}
}
public ICommand Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
protected override void Invoke(object parameter)
{
if (AssociatedObject == null)
return;
var command = ResolveCommand();
if (command == null || !command.CanExecute(CommandParameter))
return;
command.Execute(CommandParameter);
}
private ICommand ResolveCommand()
{
var command = (ICommand)null;
if (Command != null)
command = Command;
else if (AssociatedObject != null)
foreach (var property in AssociatedObject.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public))
if (typeof(ICommand).IsAssignableFrom(property.PropertyType) &&
string.Equals(property.Name, CommandName, StringComparison.Ordinal))
command = (ICommand)property.GetValue(AssociatedObject, null);
return command;
}
}
}
@@ -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,17 @@
using System;
namespace HandyControl.Interactivity
{
internal sealed class NameResolvedEventArgs : EventArgs
{
public NameResolvedEventArgs(object oldObject, object newObject)
{
OldObject = oldObject;
NewObject = newObject;
}
public object NewObject { get; }
public object OldObject { get; }
}
}
@@ -0,0 +1,124 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity
{
internal sealed class NameResolver
{
private string _name;
private FrameworkElement _nameScopeReferenceElement;
private FrameworkElement ActualNameScopeReferenceElement
{
get
{
if (NameScopeReferenceElement != null && Interaction.IsElementLoaded(NameScopeReferenceElement))
return GetActualNameScopeReference(NameScopeReferenceElement);
return null;
}
}
private bool HasAttempedResolve { get; set; }
public string Name
{
get =>
_name;
set
{
var oldObject = Object;
_name = value;
UpdateObjectFromName(oldObject);
}
}
public FrameworkElement NameScopeReferenceElement
{
get =>
_nameScopeReferenceElement;
set
{
var nameScopeReferenceElement = NameScopeReferenceElement;
_nameScopeReferenceElement = value;
OnNameScopeReferenceElementChanged(nameScopeReferenceElement);
}
}
public DependencyObject Object
{
get
{
if (string.IsNullOrEmpty(Name) && HasAttempedResolve)
return NameScopeReferenceElement;
return ResolvedObject;
}
}
private bool PendingReferenceElementLoad { get; set; }
private DependencyObject ResolvedObject { get; set; }
public event EventHandler<NameResolvedEventArgs> ResolvedElementChanged;
private FrameworkElement GetActualNameScopeReference(FrameworkElement initialReferenceElement)
{
var element = initialReferenceElement;
if (!IsNameScope(initialReferenceElement))
return element;
return initialReferenceElement.Parent as FrameworkElement ?? element;
}
private bool IsNameScope(FrameworkElement frameworkElement)
{
return frameworkElement.Parent is FrameworkElement parent && parent.FindName(Name) != null;
}
private void OnNameScopeReferenceElementChanged(FrameworkElement oldNameScopeReference)
{
if (PendingReferenceElementLoad)
{
oldNameScopeReference.Loaded -= OnNameScopeReferenceLoaded;
PendingReferenceElementLoad = false;
}
HasAttempedResolve = false;
UpdateObjectFromName(Object);
}
private void OnNameScopeReferenceLoaded(object sender, RoutedEventArgs e)
{
PendingReferenceElementLoad = false;
NameScopeReferenceElement.Loaded -= OnNameScopeReferenceLoaded;
UpdateObjectFromName(Object);
}
private void OnObjectChanged(DependencyObject oldTarget, DependencyObject newTarget)
{
ResolvedElementChanged?.Invoke(this, new NameResolvedEventArgs(oldTarget, newTarget));
}
private void UpdateObjectFromName(DependencyObject oldObject)
{
DependencyObject obj2 = null;
ResolvedObject = null;
if (NameScopeReferenceElement != null)
{
if (!Interaction.IsElementLoaded(NameScopeReferenceElement))
{
NameScopeReferenceElement.Loaded += OnNameScopeReferenceLoaded;
PendingReferenceElementLoad = true;
return;
}
if (!string.IsNullOrEmpty(Name))
{
var actualNameScopeReferenceElement = ActualNameScopeReferenceElement;
if (actualNameScopeReferenceElement != null)
obj2 = actualNameScopeReferenceElement.FindName(Name) as DependencyObject;
}
}
HasAttempedResolve = true;
ResolvedObject = obj2;
if (!Equals(oldObject, Object))
OnObjectChanged(oldObject, Object);
}
}
}
@@ -0,0 +1,9 @@
using System;
namespace HandyControl.Interactivity
{
public class PreviewInvokeEventArgs : EventArgs
{
public bool Cancelling { get; set; }
}
}
@@ -0,0 +1,29 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity
{
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
public RoutedEvent RoutedEvent { get; set; }
protected override void OnAttached()
{
var behavior = AssociatedObject as Behavior;
var associatedElement = AssociatedObject as FrameworkElement;
if (behavior != null) associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
if (associatedElement == null) throw new ArgumentException();
if (RoutedEvent != null) associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(OnRoutedEvent));
}
private void OnRoutedEvent(object sender, RoutedEventArgs args)
{
OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
}
@@ -0,0 +1,8 @@
namespace HandyControl.Interactivity
{
public enum TagType
{
Element,
DataContext
}
}
@@ -0,0 +1,56 @@
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;
namespace HandyControl.Interactivity
{
public abstract class TransitionEffect : ShaderEffect
{
// Fields
public static readonly DependencyProperty InputProperty =
RegisterPixelShaderSamplerProperty("Input", typeof(TransitionEffect), 0, SamplingMode.NearestNeighbor);
public static readonly DependencyProperty OldImageProperty =
RegisterPixelShaderSamplerProperty("OldImage", typeof(TransitionEffect), 1, SamplingMode.NearestNeighbor);
public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register("Progress",
typeof(double), typeof(TransitionEffect), new PropertyMetadata(0.0, PixelShaderConstantCallback(0)));
// Methods
protected TransitionEffect()
{
UpdateShaderValue(InputProperty);
UpdateShaderValue(OldImageProperty);
UpdateShaderValue(ProgressProperty);
}
// Properties
public Brush Input
{
get =>
(Brush) GetValue(InputProperty);
set => SetValue(InputProperty, value);
}
public Brush OldImage
{
get =>
(Brush) GetValue(OldImageProperty);
set => SetValue(OldImageProperty, value);
}
public double Progress
{
get =>
(double) GetValue(ProgressProperty);
set => SetValue(ProgressProperty, value);
}
public new TransitionEffect CloneCurrentValue()
{
return (TransitionEffect) base.CloneCurrentValue();
}
protected abstract TransitionEffect DeepCopy();
}
}
@@ -0,0 +1,19 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity
{
public abstract class TriggerAction<T> : TriggerAction where T : DependencyObject
{
protected TriggerAction() : base(typeof(T))
{
}
#pragma warning disable 108,114
protected T AssociatedObject => (T)base.AssociatedObject;
#pragma warning restore 108,114
protected sealed override Type AssociatedObjectTypeConstraint =>
base.AssociatedObjectTypeConstraint;
}
}
@@ -0,0 +1,118 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;
namespace HandyControl.Interactivity
{
[DefaultTrigger(typeof(UIElement), typeof(EventTrigger), "MouseLeftButtonDown")]
[DefaultTrigger(typeof(ButtonBase), typeof(EventTrigger), "Click")]
public abstract class TriggerAction : Animatable, IAttachedObject
{
public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled",
typeof(bool), typeof(TriggerAction), new FrameworkPropertyMetadata(true));
private readonly Type _associatedObjectTypeConstraint;
private DependencyObject _associatedObject;
private bool _isHosted;
internal TriggerAction(Type associatedObjectTypeConstraint)
{
_associatedObjectTypeConstraint = associatedObjectTypeConstraint;
}
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected virtual Type AssociatedObjectTypeConstraint
{
get
{
ReadPreamble();
return _associatedObjectTypeConstraint;
}
}
public bool IsEnabled
{
get =>
(bool) GetValue(IsEnabledProperty);
set => SetValue(IsEnabledProperty, value);
}
internal bool IsHosted
{
get
{
ReadPreamble();
return _isHosted;
}
set
{
WritePreamble();
_isHosted = value;
WritePostscript();
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerActionMultipleTimesExceptionMessage);
if (dependencyObject != null &&
!AssociatedObjectTypeConstraint.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[]
{GetType().Name, dependencyObject.GetType().Name, AssociatedObjectTypeConstraint.Name}));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
internal void CallInvoke(object parameter)
{
if (IsEnabled)
Invoke(parameter);
}
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
protected abstract void Invoke(object parameter);
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
}
@@ -0,0 +1,46 @@
using System;
using System.Windows;
namespace HandyControl.Interactivity
{
public class TriggerActionCollection : AttachableCollection<TriggerAction>
{
internal TriggerActionCollection()
{
}
protected override Freezable CreateInstanceCore()
{
return new TriggerActionCollection();
}
internal override void ItemAdded(TriggerAction item)
{
if (item.IsHosted)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerActionMultipleTimesExceptionMessage);
if (AssociatedObject != null)
item.Attach(AssociatedObject);
item.IsHosted = true;
}
internal override void ItemRemoved(TriggerAction item)
{
if (((IAttachedObject) item).AssociatedObject != null)
item.Detach();
item.IsHosted = false;
}
protected override void OnAttached()
{
foreach (var action in this)
action.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var action in this)
action.Detach();
}
}
}
@@ -0,0 +1,110 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media.Animation;
namespace HandyControl.Interactivity
{
[ContentProperty("Actions")]
public abstract class TriggerBase : Animatable, IAttachedObject
{
private static readonly DependencyPropertyKey ActionsPropertyKey =
DependencyProperty.RegisterReadOnly("Actions", typeof(TriggerActionCollection), typeof(TriggerBase),
new FrameworkPropertyMetadata());
public static readonly DependencyProperty ActionsProperty = ActionsPropertyKey.DependencyProperty;
private DependencyObject _associatedObject;
private readonly Type _associatedObjectTypeConstraint;
internal TriggerBase(Type associatedObjectTypeConstraint)
{
_associatedObjectTypeConstraint = associatedObjectTypeConstraint;
var actions = new TriggerActionCollection();
SetValue(ActionsPropertyKey, actions);
}
public TriggerActionCollection Actions =>
(TriggerActionCollection) GetValue(ActionsProperty);
protected DependencyObject AssociatedObject
{
get
{
ReadPreamble();
return _associatedObject;
}
}
protected virtual Type AssociatedObjectTypeConstraint
{
get
{
ReadPreamble();
return _associatedObjectTypeConstraint;
}
}
public void Attach(DependencyObject dependencyObject)
{
if (!Equals(dependencyObject, AssociatedObject))
{
if (AssociatedObject != null)
throw new InvalidOperationException(ExceptionStringTable
.CannotHostTriggerMultipleTimesExceptionMessage);
if (dependencyObject != null &&
!AssociatedObjectTypeConstraint.IsInstanceOfType(dependencyObject))
throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
ExceptionStringTable.TypeConstraintViolatedExceptionMessage,
new object[]
{GetType().Name, dependencyObject.GetType().Name, AssociatedObjectTypeConstraint.Name}));
WritePreamble();
_associatedObject = dependencyObject;
WritePostscript();
Actions.Attach(dependencyObject);
OnAttached();
}
}
public void Detach()
{
OnDetaching();
WritePreamble();
_associatedObject = null;
WritePostscript();
Actions.Detach();
}
DependencyObject IAttachedObject.AssociatedObject =>
AssociatedObject;
public event EventHandler<PreviewInvokeEventArgs> PreviewInvoke;
protected override Freezable CreateInstanceCore()
{
return (Freezable) Activator.CreateInstance(GetType());
}
protected void InvokeActions(object parameter)
{
if (PreviewInvoke != null)
{
var e = new PreviewInvokeEventArgs();
PreviewInvoke(this, e);
if (e.Cancelling)
return;
}
foreach (var action in Actions)
action.CallInvoke(parameter);
}
protected virtual void OnAttached()
{
}
protected virtual void OnDetaching()
{
}
}
}
@@ -0,0 +1,42 @@
using System.Windows;
namespace HandyControl.Interactivity
{
public sealed class TriggerCollection : AttachableCollection<TriggerBase>
{
internal TriggerCollection()
{
}
protected override void OnAttached()
{
foreach (var triggerBase in this)
triggerBase.Attach(AssociatedObject);
}
protected override void OnDetaching()
{
foreach (var triggerBase in this)
triggerBase.Detach();
}
internal override void ItemAdded(TriggerBase item)
{
if (AssociatedObject == null)
return;
item.Attach(AssociatedObject);
}
internal override void ItemRemoved(TriggerBase item)
{
if (((IAttachedObject) item).AssociatedObject == null)
return;
item.Detach();
}
protected override Freezable CreateInstanceCore()
{
return new TriggerCollection();
}
}
}
@@ -0,0 +1,15 @@
using System;
namespace HandyControl.Interactivity
{
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public sealed class TypeConstraintAttribute : Attribute
{
public TypeConstraintAttribute(Type constraint)
{
Constraint = constraint;
}
public Type Constraint { get; }
}
}