using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.ComponentModel; using System.Windows.Controls.Primitives; namespace Microsoft.Windows.Controls { public class DropDownButton : ContentControl, ICommandSource { #region Constructors static DropDownButton() { DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDownButton), new FrameworkPropertyMetadata(typeof(DropDownButton))); } public DropDownButton() { Keyboard.AddKeyDownHandler(this, OnKeyDown); Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnMouseDownOutsideCapturedElement); } #endregion //Constructors #region Properties private System.Windows.Controls.Primitives.ButtonBase _button; protected System.Windows.Controls.Primitives.ButtonBase Button { get { return _button; } set { if (_button != null) _button.Click -= DropDownButton_Click; _button = value; if (_button != null) _button.Click += DropDownButton_Click; } } #region DropDownContent public static readonly DependencyProperty DropDownContentProperty = DependencyProperty.Register("DropDownContent", typeof(object), typeof(DropDownButton), new UIPropertyMetadata(null, OnDropDownContentChanged)); public object DropDownContent { get { return (object)GetValue(DropDownContentProperty); } set { SetValue(DropDownContentProperty, value); } } private static void OnDropDownContentChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { DropDownButton dropDownButton = o as DropDownButton; if (dropDownButton != null) dropDownButton.OnDropDownContentChanged((object)e.OldValue, (object)e.NewValue); } protected virtual void OnDropDownContentChanged(object oldValue, object newValue) { // TODO: Add your property changed side-effects. Descendants can override as well. } #endregion //DropDownContent #region IsOpen public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(DropDownButton), new UIPropertyMetadata(false, OnIsOpenChanged)); public bool IsOpen { get { return (bool)GetValue(IsOpenProperty); } set { SetValue(IsOpenProperty, value); } } private static void OnIsOpenChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { DropDownButton dropDownButton = o as DropDownButton; if (dropDownButton != null) dropDownButton.OnIsOpenChanged((bool)e.OldValue, (bool)e.NewValue); } protected virtual void OnIsOpenChanged(bool oldValue, bool newValue) { if (newValue) RaiseRoutedEvent(DropDownButton.OpenedEvent); else RaiseRoutedEvent(DropDownButton.ClosedEvent); } #endregion //IsOpen #endregion //Properties #region Base Class Overrides public override void OnApplyTemplate() { base.OnApplyTemplate(); Button = GetTemplateChild("PART_DropDownButton") as ToggleButton; } #endregion //Base Class Overrides #region Events public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent("Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DropDownButton)); public event RoutedEventHandler Click { add { AddHandler(ClickEvent, value); } remove { RemoveHandler(ClickEvent, value); } } public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent("Opened", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DropDownButton)); 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(DropDownButton)); public event RoutedEventHandler Closed { add { AddHandler(ClosedEvent, value); } remove { RemoveHandler(ClosedEvent, value); } } #endregion //Events #region Event Handlers private void OnKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Escape: { CloseDropDown(); break; } } } private void OnMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e) { CloseDropDown(); } private void DropDownButton_Click(object sender, RoutedEventArgs e) { OnClick(); } void CanExecuteChanged(object sender, EventArgs e) { if (Command != null) { RoutedCommand command = Command as RoutedCommand; // If a RoutedCommand. if (command != null) IsEnabled = command.CanExecute(CommandParameter, CommandTarget) ? true : false; // If a not RoutedCommand. else IsEnabled = Command.CanExecute(CommandParameter) ? true : false; } } #endregion //Event Handlers #region Methods /// /// Closes the drop down. /// private void CloseDropDown() { if (IsOpen) IsOpen = false; ReleaseMouseCapture(); } protected virtual void OnClick() { RaiseRoutedEvent(DropDownButton.ClickEvent); RaiseCommand(); } /// /// Raises routed events. /// private void RaiseRoutedEvent(RoutedEvent routedEvent) { RoutedEventArgs args = new RoutedEventArgs(routedEvent, this); RaiseEvent(args); } /// /// Raises the command's Execute event. /// private void RaiseCommand() { if (Command != null) { RoutedCommand routedCommand = Command as RoutedCommand; if (routedCommand == null) ((ICommand)Command).Execute(CommandParameter); else routedCommand.Execute(CommandParameter, CommandTarget); } } /// /// Unhooks a command from the Command property. /// /// The old command. /// The new command. private void UnhookCommand(ICommand oldCommand, ICommand newCommand) { EventHandler handler = CanExecuteChanged; oldCommand.CanExecuteChanged -= handler; } /// /// Hooks up a command to the CanExecuteChnaged event handler. /// /// The old command. /// The new command. private void HookUpCommand(ICommand oldCommand, ICommand newCommand) { EventHandler handler = new EventHandler(CanExecuteChanged); canExecuteChangedHandler = handler; if (newCommand != null) newCommand.CanExecuteChanged += canExecuteChangedHandler; } #endregion //Methods #region ICommandSource Members // Keeps a copy of the CanExecuteChnaged handler so it doesn't get garbage collected. private EventHandler canExecuteChangedHandler; #region Command public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(DropDownButton), new PropertyMetadata((ICommand)null, OnCommandChanged)); [TypeConverter(typeof(CommandConverter))] public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { DropDownButton dropDownButton = d as DropDownButton; if (dropDownButton != null) dropDownButton.OnCommandChanged((ICommand)e.OldValue, (ICommand)e.NewValue); } protected virtual void OnCommandChanged(ICommand oldValue, ICommand newValue) { // If old command is not null, then we need to remove the handlers. if (oldValue != null) UnhookCommand(oldValue, newValue); HookUpCommand(oldValue, newValue); } #endregion //Command public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(DropDownButton), new PropertyMetadata(null)); public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(DropDownButton), new PropertyMetadata(null)); public IInputElement CommandTarget { get { return (IInputElement)GetValue(CommandTargetProperty); } set { SetValue(CommandTargetProperty, value); } } #endregion //ICommandSource Members } }