123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- using System;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Markup;
- using System.Windows.Media;
- using System.Windows.Media.Animation;
- using HandyControl.Data;
- using HandyControl.Interactivity;
- using HandyControl.Tools;
- namespace HandyControl.Controls;
- [ContentProperty("Content")]
- public class Drawer : FrameworkElement
- {
- private Storyboard _storyboard;
- private AdornerContainer _container;
- private ContentControl _animationControl;
- private TranslateTransform _translateTransform;
- private double _animationLength;
- private string _animationPropertyName;
- private FrameworkElement _maskElement;
- private AdornerLayer _layer;
- private UIElement _contentElement;
- private Point _contentRenderTransformOrigin;
- static Drawer()
- {
- DataContextProperty.OverrideMetadata(typeof(Drawer), new FrameworkPropertyMetadata(DataContextPropertyChanged));
- }
- public Drawer()
- {
- Loaded += Drawer_Loaded;
- }
- private void Drawer_Loaded(object sender, RoutedEventArgs e)
- {
- if (IsOpen)
- {
- OnIsOpenChanged(true);
- }
- Loaded -= Drawer_Loaded;
- }
- private static void DataContextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) =>
- ((Drawer) d).OnDataContextPropertyChanged(e);
- private void OnDataContextPropertyChanged(DependencyPropertyChangedEventArgs e) => UpdateDataContext(_animationControl, e.OldValue, e.NewValue);
- public static readonly RoutedEvent OpenedEvent =
- EventManager.RegisterRoutedEvent("Opened", RoutingStrategy.Bubble,
- typeof(RoutedEventHandler), typeof(Drawer));
- public event RoutedEventHandler Opened
- {
- add => AddHandler(OpenedEvent, value);
- remove => RemoveHandler(OpenedEvent, value);
- }
- public static readonly RoutedEvent ClosedEvent =
- EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble,
- typeof(RoutedEventHandler), typeof(Drawer));
- public event RoutedEventHandler Closed
- {
- add => AddHandler(ClosedEvent, value);
- remove => RemoveHandler(ClosedEvent, value);
- }
- public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
- nameof(IsOpen), typeof(bool), typeof(Drawer), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsOpenChanged));
- private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var ctl = (Drawer) d;
- ctl.OnIsOpenChanged((bool) e.NewValue);
- }
- public bool IsOpen
- {
- get => (bool) GetValue(IsOpenProperty);
- set => SetValue(IsOpenProperty, ValueBoxes.BooleanBox(value));
- }
- public static readonly DependencyProperty MaskCanCloseProperty = DependencyProperty.Register(
- nameof(MaskCanClose), typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
- public bool MaskCanClose
- {
- get => (bool) GetValue(MaskCanCloseProperty);
- set => SetValue(MaskCanCloseProperty, ValueBoxes.BooleanBox(value));
- }
- public static readonly DependencyProperty ShowMaskProperty = DependencyProperty.Register(
- nameof(ShowMask), typeof(bool), typeof(Drawer), new PropertyMetadata(ValueBoxes.TrueBox));
- public bool ShowMask
- {
- get => (bool) GetValue(ShowMaskProperty);
- set => SetValue(ShowMaskProperty, ValueBoxes.BooleanBox(value));
- }
- public static readonly DependencyProperty DockProperty = DependencyProperty.Register(
- nameof(Dock), typeof(Dock), typeof(Drawer), new PropertyMetadata(default(Dock)));
- public Dock Dock
- {
- get => (Dock) GetValue(DockProperty);
- set => SetValue(DockProperty, value);
- }
- public static readonly DependencyProperty ShowModeProperty = DependencyProperty.Register(
- nameof(ShowMode), typeof(DrawerShowMode), typeof(Drawer), new PropertyMetadata(default(DrawerShowMode)));
- public DrawerShowMode ShowMode
- {
- get => (DrawerShowMode) GetValue(ShowModeProperty);
- set => SetValue(ShowModeProperty, value);
- }
- public static readonly DependencyProperty MaskBrushProperty = DependencyProperty.Register(
- nameof(MaskBrush), typeof(Brush), typeof(Drawer), new PropertyMetadata(default(Brush)));
- public Brush MaskBrush
- {
- get => (Brush) GetValue(MaskBrushProperty);
- set => SetValue(MaskBrushProperty, value);
- }
- public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
- nameof(Content), typeof(object), typeof(Drawer), new PropertyMetadata(default(object)));
- public object Content
- {
- get => GetValue(ContentProperty);
- set => SetValue(ContentProperty, value);
- }
- private void CreateContainer()
- {
- _storyboard = new Storyboard();
- _storyboard.Completed += Storyboard_Completed;
- _translateTransform = new TranslateTransform();
- _animationControl = new ContentControl
- {
- Content = Content,
- RenderTransform = _translateTransform,
- DataContext = this
- };
- var panel = new SimplePanel
- {
- ClipToBounds = true
- };
- if (ShowMask)
- {
- _maskElement = new Border
- {
- Background = MaskBrush,
- Opacity = 0
- };
- _maskElement.PreviewMouseLeftButtonDown += MaskElement_PreviewMouseLeftButtonDown;
- panel.Children.Add(_maskElement);
- }
- _animationControl.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
- var size = _animationControl.DesiredSize;
- switch (Dock)
- {
- case Dock.Left:
- _animationControl.HorizontalAlignment = HorizontalAlignment.Left;
- _animationControl.VerticalAlignment = VerticalAlignment.Stretch;
- _translateTransform.X = -size.Width;
- _animationLength = -size.Width;
- _animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
- break;
- case Dock.Top:
- _animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
- _animationControl.VerticalAlignment = VerticalAlignment.Top;
- _translateTransform.Y = -size.Height;
- _animationLength = -size.Height;
- _animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
- break;
- case Dock.Right:
- _animationControl.HorizontalAlignment = HorizontalAlignment.Right;
- _animationControl.VerticalAlignment = VerticalAlignment.Stretch;
- _translateTransform.X = size.Width;
- _animationLength = size.Width;
- _animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
- break;
- case Dock.Bottom:
- _animationControl.HorizontalAlignment = HorizontalAlignment.Stretch;
- _animationControl.VerticalAlignment = VerticalAlignment.Bottom;
- _translateTransform.Y = size.Height;
- _animationLength = size.Height;
- _animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- _animationControl.DataContext = DataContext;
- _animationControl.CommandBindings.Clear();
- _animationControl.CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox)));
- panel.Children.Add(_animationControl);
- _container = new AdornerContainer(_layer)
- {
- Child = panel,
- ClipToBounds = true
- };
- }
- private void Storyboard_Completed(object sender, EventArgs e)
- {
- if (!IsOpen)
- {
- _contentElement.SetCurrentValue(RenderTransformOriginProperty, _contentRenderTransformOrigin);
- _layer.Remove(_container);
- RaiseEvent(new RoutedEventArgs(ClosedEvent, this));
- }
- else
- {
- RaiseEvent(new RoutedEventArgs(OpenedEvent, this));
- }
- }
- private void OnIsOpenChanged(bool isOpen)
- {
- if (Content == null || DesignerHelper.IsInDesignMode)
- {
- return;
- }
- AdornerDecorator decorator;
- var parent = VisualHelper.GetParent<DrawerContainer>(this);
- if (parent != null)
- {
- _contentElement = parent.Child;
- decorator = parent;
- }
- else
- {
- var window = WindowHelper.GetActiveWindow();
- if (window == null)
- {
- return;
- }
- decorator = VisualHelper.GetChild<AdornerDecorator>(window);
- _contentElement = window.Content as UIElement;
- }
- if (_contentElement == null)
- {
- return;
- }
- _layer = decorator?.AdornerLayer;
- if (_layer == null)
- {
- return;
- }
- _contentRenderTransformOrigin = _contentElement.RenderTransformOrigin;
- if (_container == null)
- {
- CreateContainer();
- }
- switch (ShowMode)
- {
- case DrawerShowMode.Push:
- ShowByPush(isOpen);
- break;
- case DrawerShowMode.Press:
- _contentElement.SetCurrentValue(RenderTransformOriginProperty, new Point(0.5, 0.5));
- ShowByPress(isOpen);
- break;
- }
- if (isOpen)
- {
- if (_maskElement != null)
- {
- var maskAnimation = AnimationHelper.CreateAnimation(1);
- Storyboard.SetTarget(maskAnimation, _maskElement);
- Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
- _storyboard.Children.Add(maskAnimation);
- }
- var drawerAnimation = AnimationHelper.CreateAnimation(0);
- Storyboard.SetTarget(drawerAnimation, _animationControl);
- Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
- _storyboard.Children.Add(drawerAnimation);
- _layer.Remove(_container);
- _layer.Add(_container);
- }
- else
- {
- if (_maskElement != null)
- {
- var maskAnimation = AnimationHelper.CreateAnimation(0);
- Storyboard.SetTarget(maskAnimation, _maskElement);
- Storyboard.SetTargetProperty(maskAnimation, new PropertyPath(OpacityProperty.Name));
- _storyboard.Children.Add(maskAnimation);
- }
- var drawerAnimation = AnimationHelper.CreateAnimation(_animationLength);
- Storyboard.SetTarget(drawerAnimation, _animationControl);
- Storyboard.SetTargetProperty(drawerAnimation, new PropertyPath(_animationPropertyName));
- _storyboard.Children.Add(drawerAnimation);
- }
- _storyboard.Begin();
- }
- private void ShowByPush(bool isOpen)
- {
- string animationPropertyName;
- switch (Dock)
- {
- case Dock.Left:
- case Dock.Right:
- animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.X)";
- _contentElement.RenderTransform = new TranslateTransform
- {
- X = isOpen ? 0 : -_animationLength
- };
- break;
- case Dock.Top:
- case Dock.Bottom:
- animationPropertyName = "(UIElement.RenderTransform).(TranslateTransform.Y)";
- _contentElement.RenderTransform = new TranslateTransform
- {
- Y = isOpen ? 0 : -_animationLength
- };
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- var animation = isOpen
- ? AnimationHelper.CreateAnimation(-_animationLength)
- : AnimationHelper.CreateAnimation(0);
- Storyboard.SetTarget(animation, _contentElement);
- Storyboard.SetTargetProperty(animation, new PropertyPath(animationPropertyName));
- _storyboard.Children.Add(animation);
- }
- private void ShowByPress(bool isOpen)
- {
- _contentElement.RenderTransform = isOpen
- ? new ScaleTransform()
- : new ScaleTransform
- {
- ScaleX = 0.9,
- ScaleY = 0.9
- };
- var animationX = isOpen
- ? AnimationHelper.CreateAnimation(.9)
- : AnimationHelper.CreateAnimation(1);
- Storyboard.SetTarget(animationX, _contentElement);
- Storyboard.SetTargetProperty(animationX, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleX)"));
- _storyboard.Children.Add(animationX);
- var animationY = isOpen
- ? AnimationHelper.CreateAnimation(.9)
- : AnimationHelper.CreateAnimation(1);
- Storyboard.SetTarget(animationY, _contentElement);
- Storyboard.SetTargetProperty(animationY, new PropertyPath("(UIElement.RenderTransform).(ScaleTransform.ScaleY)"));
- _storyboard.Children.Add(animationY);
- }
- private void MaskElement_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- if (MaskCanClose)
- {
- SetCurrentValue(IsOpenProperty, ValueBoxes.FalseBox);
- }
- }
- private void UpdateDataContext(FrameworkElement target, object oldValue, object newValue)
- {
- if (target == null || BindingOperations.GetBindingExpression(target, DataContextProperty) != null) return;
- if (ReferenceEquals(this, target.DataContext) || Equals(oldValue, target.DataContext))
- {
- target.DataContext = newValue ?? this;
- }
- }
- }
|