Skip to content

Instantly share code, notes, and snippets.

@Torvin
Created October 10, 2015 09:34
Show Gist options
  • Save Torvin/686f3b3d8d15af854018 to your computer and use it in GitHub Desktop.
Save Torvin/686f3b3d8d15af854018 to your computer and use it in GitHub Desktop.
ExpandableContentControl
public class ExpandableContentControl : ContentControl
{
static ExpandableContentControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ExpandableContentControl), new FrameworkPropertyMetadata(typeof(ExpandableContentControl)));
ClipToBoundsProperty.OverrideMetadata(typeof(ExpandableContentControl), new FrameworkPropertyMetadata(true));
FocusableProperty.OverrideMetadata(typeof(ExpandableContentControl), new FrameworkPropertyMetadata(false));
}
#region public ExpandDirection RevealMode
/// <summary>
/// Gets or sets the direction in which the ExpandableContentControl
/// content window opens.
/// </summary>
public ExpandDirection RevealMode
{
get { return (ExpandDirection)GetValue(RevealModeProperty); }
set { SetValue(RevealModeProperty, value); }
}
/// <summary>
/// Identifies the RevealMode dependency property.
/// </summary>
public static readonly DependencyProperty RevealModeProperty = DependencyProperty.Register("RevealMode", typeof(ExpandDirection), typeof(ExpandableContentControl),
new FrameworkPropertyMetadata(ExpandDirection.Down, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange), IsRevealModeValid);
private static bool IsRevealModeValid(object value)
{
return value != null && Enum.IsDefined(typeof(ExpandDirection), value);
}
/// <summary>
/// Gets a value indicating whether the content should be revealed horizontally.
/// </summary>
private bool IsHorizontalRevealMode
{
get { return RevealMode == ExpandDirection.Left || RevealMode == ExpandDirection.Right; }
}
#endregion public ExpandDirection RevealMode
#region public double Percentage
/// <summary>
/// Gets or sets the relative percentage of the content that is
/// currently visible. A percentage of 1 corresponds to the complete
/// TargetSize.
/// </summary>
public double Percentage
{
get { return (double)GetValue(PercentageProperty); }
set { SetValue(PercentageProperty, value); }
}
/// <summary>
/// Identifies the Percentage dependency property.
/// </summary>
public static readonly DependencyProperty PercentageProperty = DependencyProperty.Register("Percentage", typeof(double), typeof(ExpandableContentControl),
new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
#endregion public double Percentage
#region IsExpanded
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(bool), typeof(ExpandableContentControl), new PropertyMetadata(false));
public bool IsExpanded
{
get { return (bool)GetValue(IsExpandedProperty); }
set { SetValue(IsExpandedProperty, value); }
}
#endregion
private UIElement Child
{
get { return VisualChildrenCount == 0 ? null : GetVisualChild(0) as UIElement; }
}
protected override Size MeasureOverride(Size availableSize)
{
var child = Child;
var size = new Size();
if (child != null)
{
child.Measure(availableSize);
size = child.DesiredSize;
}
return Resize(size, Percentage);
}
private Size Resize(Size size, double factor)
{
return IsHorizontalRevealMode
? new Size(size.Width * factor, size.Height)
: new Size(size.Width, size.Height * factor);
}
protected override Size ArrangeOverride(Size finalSize)
{
var child = Child;
if (child == null || Math.Abs(Percentage) < 0.0001)
return finalSize;
var rect = new Rect(Resize(finalSize, 1 / Percentage));
if (RevealMode == ExpandDirection.Down)
rect.Y = -rect.Height * (1 - Percentage);
else if (RevealMode == ExpandDirection.Left)
rect.X = -rect.Width * (1 - Percentage);
child.Arrange(rect);
return finalSize;
}
}
<Style TargetType="me:ExpandableContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="me:ExpandableContentControl">
<ControlTemplate.Resources>
<ExponentialEase x:Key="Ease" Exponent="3" EasingMode="EaseOut" />
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="False">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="1" To="0" Duration="00:00:00.2" Storyboard.TargetProperty="Percentage" EasingFunction="{StaticResource Ease}" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="1" Duration="00:00:00.2" Storyboard.TargetProperty="Percentage" EasingFunction="{StaticResource Ease}" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment