using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Animation;
namespace MefBasic.UserControls
{
public partial class CollapsibleContainer
{
private const string LeftIcon = "LeftIcon";
private const string RightIcon = "RightIcon";
private const string UpIcon = "UpIcon";
private const string DownIcon = "DownIcon";
private const double Delay = 0.25;
public static readonly DependencyProperty IsExpandedProperty =
DependencyProperty.Register("IsExpanded", typeof (bool), typeof (CollapsibleContainer),
new UIPropertyMetadata(true, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (CollapsibleContainer) d;
control.DoPropertyChanged(e);
}
private void DoPropertyChanged(DependencyPropertyChangedEventArgs e)
{
switch (e.Property.Name)
{
case "IsExpanded":
RefreshView();
break;
case "Child":
childContentControl.Content = Child;
break;
case "Direction":
HideAllBorder();
RefreshView();
break;
}
}
private void HideAllBorder()
{
btnLeft.Visibility = Visibility.Collapsed;
btnTop.Visibility = Visibility.Collapsed;
btnRight.Visibility = Visibility.Collapsed;
btnBottom.Visibility = Visibility.Collapsed;
}
public static readonly DependencyProperty ChildProperty =
DependencyProperty.Register("Child", typeof (object), typeof (CollapsibleContainer),
new UIPropertyMetadata(null,OnPropertyChanged));
private double _delay;
private Point _initialMousePosition;
private bool _isDragging;
private bool _isLoaded;
public CollapsibleContainer()
{
InitializeComponent();
InitializeMyComponent();
imgLeft.Content = FindResource(LeftIcon);
imgTop.Content = FindResource(UpIcon);
imgRight.Content = FindResource(RightIcon);
imgBottom.Content = FindResource(DownIcon);
}
public bool IsAnimationOn { set; get; }
public bool CanCollapse { get; set; }
public bool IsExpanded
{
get { return (bool) GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
public object Child
{
get { return GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); }
}
public event EventHandler AnimationCompleted;
private void InitializeMyComponent()
{
IsAnimationOn = true;
SubscribeMouseDown();
contentHolder.Loaded += HandleLoaded;
contentHolder.SizeChanged += HandleContentHolderSizeChanged;
_delay = Delay;
}
private void HandleContentHolderSizeChanged(object sender, SizeChangedEventArgs e)
{
if (ContentSize==0)
ContentSize = Math.Max(ContentSize, GetActualSize());
}
private void SubscribeMouseDown()
{
imgLeft.PreviewMouseDown += BtnShowHideMouseUp;
imgTop.PreviewMouseDown += BtnShowHideMouseUp;
imgRight.PreviewMouseDown += BtnShowHideMouseUp;
imgBottom.PreviewMouseDown += BtnShowHideMouseUp;
}
private double GetActualSize()
{
switch (Direction)
{
case Direction.LeftToRight:
case Direction.RightToLeft:
return contentHolder.ActualWidth;
case Direction.TopToBottom:
case Direction.BottomToTop:
return contentHolder.ActualHeight;
}
return 0;
}
private void HandleLoaded(object sender, RoutedEventArgs e)
{
if (_isLoaded) return;
_isLoaded = true;
ContentSize = GetActualSize();
UpdateImage();
}
private void OnAnimationCompleted()
{
if (AnimationCompleted != null)
{
AnimationCompleted(this, new EventArgs());
}
}
private void BtnShowHideMouseUp(object sender, MouseButtonEventArgs e)
{
IsExpanded = !IsExpanded;
RefreshView();
e.Handled = true;
}
public ICommand ExpandCollapseChangedCommand
{
get { return (ICommand)GetValue(ExpandCollapseChangedCommandProperty); }
set { SetValue(ExpandCollapseChangedCommandProperty, value); }
}
public static readonly DependencyProperty ExpandCollapseChangedCommandProperty =
DependencyProperty.Register("ExpandCollapseChangedCommand", typeof(ICommand), typeof(CollapsibleContainer), new UIPropertyMetadata(null));
public object ExpandCollapseChangedCommandParameter
{
get { return (object)GetValue(ExpandCollapseChangedCommandParameterProperty); }
set { SetValue(ExpandCollapseChangedCommandParameterProperty, value); }
}
public static readonly DependencyProperty ExpandCollapseChangedCommandParameterProperty =
DependencyProperty.Register("ExpandCollapseChangedCommandParameter", typeof(object), typeof(CollapsibleContainer), new UIPropertyMetadata(null));
private void RefreshView()
{
UpdateImage();
if (IsExpanded)
Expand();
else
Collapse();
}
public void SetSizable(bool isSizable)
{
if (isSizable)
{
SubscribeEventsForSizable(btnLeft);
SubscribeEventsForSizable(btnTop);
SubscribeEventsForSizable(btnRight);
SubscribeEventsForSizable(btnBottom);
}
else
{
UnsubscribeEventsForSizable(btnLeft);
UnsubscribeEventsForSizable(btnTop);
UnsubscribeEventsForSizable(btnRight);
UnsubscribeEventsForSizable(btnBottom);
}
}
private void UnsubscribeEventsForSizable(Border border)
{
border.MouseMove -= OnBorderMouseMove;
border.MouseLeftButtonDown -= OnBorderMouseLeftButtonDown;
border.MouseLeftButtonUp -= OnBorderMouseLeftButtonUp;
border.Cursor = Cursors.Arrow;
}
private void SubscribeEventsForSizable(Border border)
{
border.MouseMove += OnBorderMouseMove;
border.MouseLeftButtonDown += OnBorderMouseLeftButtonDown;
border.MouseLeftButtonUp += OnBorderMouseLeftButtonUp;
border.Cursor = Cursors.SizeWE;
}
public void Collapse()
{
if (!_isLoaded) return;
if (IsAnimationOn)
{
Animate(ContentSize, 0);
}
else
{
contentHolder.Visibility = Visibility.Collapsed;
}
}
public void Expand()
{
if (!_isLoaded) return;
if (IsAnimationOn)
{
Animate(0, ContentSize);
}
else
{
contentHolder.Visibility = Visibility.Visible;
}
}
public Direction Direction
{
get { return (Direction)GetValue(DirectionProperty); }
set { SetValue(DirectionProperty, value); }
}
public double ContentSize { get; set; }
public static readonly DependencyProperty DirectionProperty =
DependencyProperty.Register("Direction", typeof(Direction), typeof(CollapsibleContainer), new UIPropertyMetadata(Direction.LeftToRight,OnPropertyChanged));
public void Animate(double from, double to)
{
var dbAnimation = new DoubleAnimation();
dbAnimation.Completed += DoubleAnimationCompleted;
dbAnimation.From = from;
dbAnimation.To = to;
dbAnimation.Duration = new Duration(TimeSpan.FromSeconds(_delay));
switch (Direction)
{
case Direction.LeftToRight:
case Direction.RightToLeft:
contentContainer.BeginAnimation(WidthProperty, dbAnimation);
break;
case Direction.TopToBottom:
case Direction.BottomToTop:
contentContainer.BeginAnimation(HeightProperty, dbAnimation);
break;
}
}
private void DoubleAnimationCompleted(object sender, EventArgs e)
{
UpdateImage();
_delay = Delay;
if (!_isDragging)
{
OnAnimationCompleted();
}
if (ExpandCollapseChangedCommand != null)
{
ExpandCollapseChangedCommand.Execute(ExpandCollapseChangedCommandParameter);
}
}
private void UpdateImage()
{
switch (Direction)
{
case Direction.LeftToRight:
btnLeft.Visibility = Visibility.Visible;
imgLeft.Content = FindResource(IsExpanded ? RightIcon : LeftIcon);
break;
case Direction.RightToLeft:
btnRight.Visibility = Visibility.Visible;
imgRight.Content = FindResource(IsExpanded ? LeftIcon : RightIcon);
break;
case Direction.TopToBottom:
btnTop.Visibility = Visibility.Visible;
imgTop.Content = FindResource(IsExpanded ? DownIcon : UpIcon);
break;
case Direction.BottomToTop:
btnBottom.Visibility = Visibility.Visible;
imgBottom.Content = FindResource(IsExpanded ? UpIcon : DownIcon);
break;
}
}
private void OnBorderMouseMove(object sender, MouseEventArgs e)
{
if (!IsExpanded) return;
if (e.LeftButton != MouseButtonState.Pressed) return;
var currentPosition = e.GetPosition(this);
var deltaX = currentPosition.X - _initialMousePosition.X;
var absDelta = Math.Abs(deltaX);
if (absDelta < SystemParameters.MinimumHorizontalDragDistance) return;
if (!_isDragging)
{
_isDragging = true;
}
_initialMousePosition = currentPosition;
var currentWidth = contentHolder.ActualWidth;
var newWidth = contentHolder.ActualWidth;
if (IsWidthIncreasing(deltaX))
{
if ((newWidth + absDelta) <= (Application.Current.MainWindow.ActualWidth/2))
newWidth += absDelta;
}
else
{
if (newWidth - absDelta >= contentHolder.MinWidth)
newWidth -= absDelta;
}
_delay = 0;
Animate(currentWidth, newWidth);
}
private bool IsWidthIncreasing(double deltaX)
{
if (Direction == Direction.RightToLeft)
{
return deltaX > 0;
}
return deltaX < 0;
}
private void OnBorderMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var border = (Border) sender;
Mouse.Capture(border);
_initialMousePosition = e.GetPosition(this);
}
private void OnBorderMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_isDragging = false;
Mouse.Capture(null);
}
}
}