Skip to content

Commit

Permalink
Merge pull request #1945 from MahApps/ToggleSwitch-improvements
Browse files Browse the repository at this point in the history
ToggleSwitch improvements and fixes
  • Loading branch information
punker76 committed Jun 1, 2015
2 parents 3c005ff + 9ffc0b4 commit c60f060
Show file tree
Hide file tree
Showing 6 changed files with 399 additions and 130 deletions.
198 changes: 171 additions & 27 deletions MahApps.Metro/Controls/ToggleSwitch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using MahApps.Metro.Converters;

Expand All @@ -29,16 +30,34 @@ public class ToggleSwitch : ContentControl
private const string SwitchPart = "Switch";

private ToggleButton _toggleButton;
private bool _wasContentSet;

public static readonly DependencyProperty OnLabelProperty = DependencyProperty.Register("OnLabel", typeof(string), typeof(ToggleSwitch), new PropertyMetadata("On"));
public static readonly DependencyProperty OffLabelProperty = DependencyProperty.Register("OffLabel", typeof(string), typeof(ToggleSwitch), new PropertyMetadata("Off"));
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(object), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty SwitchForegroundProperty = DependencyProperty.Register("SwitchForeground", typeof(Brush), typeof(ToggleSwitch), null);

[Obsolete(@"This property will be deleted in the next release. You should use OnSwitchBrush and OffSwitchBrush to change the switch's brushes.")]
public static readonly DependencyProperty SwitchForegroundProperty = DependencyProperty.Register("SwitchForeground", typeof(Brush), typeof(ToggleSwitch), new PropertyMetadata(null, (o, e) => ((ToggleSwitch)o).OnSwitchBrush = e.NewValue as Brush));
public static readonly DependencyProperty OnSwitchBrushProperty = DependencyProperty.Register("OnSwitchBrush", typeof(Brush), typeof(ToggleSwitch), null);
public static readonly DependencyProperty OffSwitchBrushProperty = DependencyProperty.Register("OffSwitchBrush", typeof(Brush), typeof(ToggleSwitch), null);

public static readonly DependencyProperty ThumbIndicatorBrushProperty = DependencyProperty.Register("ThumbIndicatorBrush", typeof(Brush), typeof(ToggleSwitch), null);
public static readonly DependencyProperty ThumbIndicatorDisabledBrushProperty = DependencyProperty.Register("ThumbIndicatorDisabledBrush", typeof(Brush), typeof(ToggleSwitch), null);
public static readonly DependencyProperty ThumbIndicatorWidthProperty = DependencyProperty.Register("ThumbIndicatorWidth", typeof(double), typeof(ToggleSwitch), new PropertyMetadata(13d));

public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool?), typeof(ToggleSwitch), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsCheckedChanged));

public static readonly DependencyProperty CheckChangedCommandProperty = DependencyProperty.Register("CheckChangedCommand", typeof(ICommand), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty CheckedCommandProperty = DependencyProperty.Register("CheckedCommand", typeof(ICommand), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty UnCheckedCommandProperty = DependencyProperty.Register("UnCheckedCommand", typeof(ICommand), typeof(ToggleSwitch), new PropertyMetadata(null));

public static readonly DependencyProperty CheckChangedCommandParameterProperty = DependencyProperty.Register("CheckChangedCommandParameter", typeof(object), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty CheckedCommandParameterProperty = DependencyProperty.Register("CheckedCommandParameter", typeof(object), typeof(ToggleSwitch), new PropertyMetadata(null));
public static readonly DependencyProperty UnCheckedCommandParameterProperty = DependencyProperty.Register("UnCheckedCommandParameter", typeof(object), typeof(ToggleSwitch), new PropertyMetadata(null));

// LeftToRight means content left and button right and RightToLeft vise versa
public static readonly DependencyProperty ContentDirectionProperty = DependencyProperty.Register("ContentDirection", typeof(FlowDirection), typeof(ToggleSwitch), new PropertyMetadata(FlowDirection.LeftToRight));
public static readonly DependencyProperty ToggleSwitchButtonStyleProperty = DependencyProperty.Register("ToggleSwitchButtonStyle", typeof(Style), typeof(ToggleSwitch), new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure));

public event EventHandler<RoutedEventArgs> Checked;
public event EventHandler<RoutedEventArgs> Unchecked;
Expand Down Expand Up @@ -84,23 +103,76 @@ public DataTemplate HeaderTemplate
/// <summary>
/// Gets/sets the brush used for the switch's foreground.
/// </summary>
[Obsolete(@"This property will be deleted in the next release. You should use OnSwitchBrush and OffSwitchBrush to change the switch's brushes.")]
public Brush SwitchForeground
{
get { return (Brush)GetValue(SwitchForegroundProperty); }
set
{
SetValue(SwitchForegroundProperty, value);
}
set { SetValue(SwitchForegroundProperty, value); }
}

/// <summary>
/// Gets/sets the brush used for the on-switch's foreground.
/// </summary>
public Brush OnSwitchBrush
{
get { return (Brush)GetValue(OnSwitchBrushProperty); }
set { SetValue(OnSwitchBrushProperty, value); }
}

/// <summary>
/// Gets/sets the brush used for the off-switch's foreground.
/// </summary>
public Brush OffSwitchBrush
{
get { return (Brush)GetValue(OffSwitchBrushProperty); }
set { SetValue(OffSwitchBrushProperty, value); }
}

/// <summary>
/// Gets/sets the brush used for the thumb indicator.
/// </summary>
public Brush ThumbIndicatorBrush
{
get { return (Brush)GetValue(ThumbIndicatorBrushProperty); }
set { SetValue(ThumbIndicatorBrushProperty, value); }
}

/// <summary>
/// Gets/sets the brush used for the thumb indicator.
/// </summary>
public Brush ThumbIndicatorDisabledBrush
{
get { return (Brush)GetValue(ThumbIndicatorDisabledBrushProperty); }
set { SetValue(ThumbIndicatorDisabledBrushProperty, value); }
}

/// <summary>
/// Gets/sets the width of the thumb indicator.
/// </summary>
public double ThumbIndicatorWidth
{
get { return (double)GetValue(ThumbIndicatorWidthProperty); }
set { SetValue(ThumbIndicatorWidthProperty, value); }
}

/// <summary>
/// Gets/sets the control's content flow direction.
/// </summary>
public FlowDirection ContentDirection {
public FlowDirection ContentDirection
{
get { return (FlowDirection)GetValue(ContentDirectionProperty); }
set { SetValue(ContentDirectionProperty, value); }
}

/// <summary>
/// Gets/sets the control's toggle switch button style.
/// </summary>
public Style ToggleSwitchButtonStyle
{
get { return (Style)GetValue(ToggleSwitchButtonStyleProperty); }
set { SetValue(ToggleSwitchButtonStyleProperty, value); }
}

/// <summary>
/// Gets/sets whether the control is Checked (On) or not (Off).
/// </summary>
Expand All @@ -111,6 +183,60 @@ public bool? IsChecked
set { SetValue(IsCheckedProperty, value); }
}

/// <summary>
/// Gets/sets the command which will be executed if the IsChecked property was changed.
/// </summary>
public ICommand CheckChangedCommand
{
get { return (ICommand)GetValue(CheckChangedCommandProperty); }
set { SetValue(CheckChangedCommandProperty, value); }
}

/// <summary>
/// Gets/sets the command which will be executed if the checked event of the control is fired.
/// </summary>
public ICommand CheckedCommand
{
get { return (ICommand)GetValue(CheckedCommandProperty); }
set { SetValue(CheckedCommandProperty, value); }
}

/// <summary>
/// Gets/sets the command which will be executed if the checked event of the control is fired.
/// </summary>
public ICommand UnCheckedCommand
{
get { return (ICommand)GetValue(UnCheckedCommandProperty); }
set { SetValue(UnCheckedCommandProperty, value); }
}

/// <summary>
/// Gets/sets the command parameter which will be passed by the CheckChangedCommand.
/// </summary>
public object CheckChangedCommandParameter
{
get { return (object)GetValue(CheckChangedCommandParameterProperty); }
set { SetValue(CheckChangedCommandParameterProperty, value); }
}

/// <summary>
/// Gets/sets the command parameter which will be passed by the CheckedCommand.
/// </summary>
public object CheckedCommandParameter
{
get { return (object)GetValue(CheckedCommandParameterProperty); }
set { SetValue(CheckedCommandParameterProperty, value); }
}

/// <summary>
/// Gets/sets the command parameter which will be passed by the UnCheckedCommand.
/// </summary>
public object UnCheckedCommandParameter
{
get { return (object)GetValue(UnCheckedCommandParameterProperty); }
set { SetValue(UnCheckedCommandParameterProperty, value); }
}

/// <summary>
/// An event that is raised when the value of IsChecked changes.
/// </summary>
Expand All @@ -124,9 +250,20 @@ private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyCha
var oldValue = (bool?)e.OldValue;
var newValue = (bool?)e.NewValue;

if (oldValue != newValue && toggleSwitch.IsCheckedChanged != null)
if (oldValue != newValue)
{
toggleSwitch.IsCheckedChanged(toggleSwitch, EventArgs.Empty);
var command = toggleSwitch.CheckChangedCommand;
var commandParameter = toggleSwitch.CheckChangedCommandParameter ?? toggleSwitch;
if (command != null && command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}

var eh = toggleSwitch.IsCheckedChanged;
if (eh != null)
{
eh(toggleSwitch, EventArgs.Empty);
}
}
}
}
Expand All @@ -136,40 +273,24 @@ public ToggleSwitch()
DefaultStyleKey = typeof(ToggleSwitch);

PreviewKeyUp += ToggleSwitch_PreviewKeyUp;
MouseUp += (sender, args) => Keyboard.Focus(this);
}

void ToggleSwitch_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Space && e.OriginalSource == sender)
IsChecked = !IsChecked;
}

private void SetDefaultContent()
{
Binding binding = new Binding("IsChecked") { Source = this, Converter = new OffOnConverter(), ConverterParameter = this };
SetBinding(ContentProperty, binding);
IsChecked = !IsChecked;
}

private void ChangeVisualState(bool useTransitions)
{
VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, useTransitions);
}

protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
_wasContentSet = true;
}

public override void OnApplyTemplate()
{
base.OnApplyTemplate();

if (!_wasContentSet && GetBindingExpression(ContentProperty) == null)
{
SetDefaultContent();
}

if (_toggleButton != null)
{
_toggleButton.Checked -= CheckedHandler;
Expand All @@ -179,6 +300,8 @@ public override void OnApplyTemplate()
BindingOperations.ClearBinding(_toggleButton, ToggleButton.IsCheckedProperty);

_toggleButton.IsEnabledChanged -= IsEnabledHandler;

_toggleButton.PreviewMouseUp -= this.ToggleButtonPreviewMouseUp;
}
_toggleButton = GetTemplateChild(SwitchPart) as ToggleButton;
if (_toggleButton != null)
Expand All @@ -191,22 +314,43 @@ public override void OnApplyTemplate()
_toggleButton.SetBinding(ToggleButton.IsCheckedProperty, binding);

_toggleButton.IsEnabledChanged += IsEnabledHandler;

_toggleButton.PreviewMouseUp += this.ToggleButtonPreviewMouseUp;
}
ChangeVisualState(false);
}

private void ToggleButtonPreviewMouseUp(object sender, MouseButtonEventArgs e)
{
Keyboard.Focus(this);
}

private void IsEnabledHandler(object sender, DependencyPropertyChangedEventArgs e)
{
ChangeVisualState(false);
}

private void CheckedHandler(object sender, RoutedEventArgs e)
{
var command = this.CheckedCommand;
var commandParameter = this.CheckedCommandParameter ?? this;
if (command != null && command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}

SafeRaise.Raise(Checked, this, e);
}

private void UncheckedHandler(object sender, RoutedEventArgs e)
{
var command = this.UnCheckedCommand;
var commandParameter = this.UnCheckedCommandParameter ?? this;
if (command != null && command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}

SafeRaise.Raise(Unchecked, this, e);
}

Expand Down
Loading

0 comments on commit c60f060

Please sign in to comment.