Может ли пользовательский элемент управления WPF реализовать свойство IsDefault - PullRequest
3 голосов
/ 14 апреля 2010

У меня есть пользовательский элемент управления Button, который не является производным от Button. Могу ли я реализовать эквивалент IsDefault , чтобы была вызвана команда, связанная с моим элементом управления. Я надеялся, что это было прикрепленное свойство, которое я мог бы добавить к любому элементу управления, но, насколько я могу судить, это не так. Мне не повезло, если мой контроль не происходит от Баттона или есть хотя бы разумный обходной путь?

UPDATE: Я только что посмотрел с отражателем на то, как это делается под кнопкой, и я должен сказать, что это не самый понятный код, который я видел. Похоже, что есть как минимум 3 свойства зависимостей и несколько пользовательских типов только для того, чтобы обработать концепцию Button по умолчанию. Поскольку, кажется, не существует существующего способа заимствовать функциональность IsDefault, я полагаю, мне придется сузить то, что я пытаюсь достичь, чтобы я мог, по крайней мере, заставить работать фокус по умолчанию и обрабатывать ключи доступа и просто игнорировать сложность, включенная в реализацию Button.IsDefault.

UPDATE: Добавлен следующий пример кода, показывающий мою безуспешную попытку попробовать предложения itowlson .

MyButton.xaml

<UserControl x:Class="IsDefault.MyButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             Height="28"
             Width="117">

    <Grid>
        <Button Click="Button_Click">
            <Button.Template>
                <ControlTemplate>
                    <Border BorderThickness="2"
                            CornerRadius="12"
                            Background="DarkSlateBlue">
                        <TextBlock Foreground="WhiteSmoke"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center">Some Text</TextBlock>
                    </Border>
                </ControlTemplate>
            </Button.Template>
        </Button>
    </Grid>
</UserControl>

MyButton.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace IsDefault
{
    /// <summary>
    /// Interaction logic for MyButton.xaml
    /// </summary>
    public partial class MyButton : UserControl
    {


        // Provide CLR accessors for the event
        public event RoutedEventHandler Click
        {
            add { AddHandler(ClickEvent, value); }
            remove { RemoveHandler(ClickEvent, value); }
        }

        // Using a RoutedEvent
        public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent(
            "Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButton));



        public bool IsDefault
        {
            get { return (bool)GetValue(IsDefaultProperty); }
            set { SetValue(IsDefaultProperty, value); }
        }

        public static readonly DependencyProperty IsDefaultProperty =
            DependencyProperty.Register(
                "IsDefault", 
                typeof(bool),
                typeof(MyButton),
                new PropertyMetadata(false, IsDefault_PropertyChangedCallback, null));


        public MyButton()
        {
            InitializeComponent();
        }

        protected override void OnAccessKey(AccessKeyEventArgs e)
        {
            base.OnAccessKey(e);

            if (e.Key == "\r")
            {
                if (e.IsMultiple)
                {
                    // There are multiple controls that are currently handling the Enter key
                    MessageBox.Show("there are multiple controls handling the Enter key.");
                }
                else
                {
                    RaiseEvent(new RoutedEventArgs(ClickEvent, this));
                }
            }
        }

        private static void IsDefault_PropertyChangedCallback(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var button = d as MyButton;

            var isDefault = (bool)e.NewValue;

            if (isDefault)
            {
                AccessKeyManager.Register("\r", button);
            }
            else
            {
                AccessKeyManager.Unregister("\r", button);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            RaiseEvent(new RoutedEventArgs(ClickEvent));
        }
    }
}

MainWindow.xaml

<Window x:Class="IsDefault.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:my="clr-namespace:IsDefault">
    <Grid>
        <Button Content="Button"
                Height="23"
                HorizontalAlignment="Left"
                Margin="224,24,0,0"
                Name="button1"
                VerticalAlignment="Top"
                Width="75" />
        <TextBox Height="23"
                 HorizontalAlignment="Left"
                 Margin="208,94,0,0"
                 Name="textBox1"
                 VerticalAlignment="Top"
                 Width="120" />
        <my:MyButton Height="28"
                     HorizontalAlignment="Left"
                     Margin="232,154,0,0"
                     x:Name="myButton1"
                     VerticalAlignment="Top"
                     Width="117"
                     Click="myButton1_Click"
                     IsDefault="True"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace IsDefault
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void myButton1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("My button was clicked, yay!");
        }
    }
}

Ответы [ 2 ]

5 голосов
/ 14 апреля 2010

Все, что делает установка Button.IsDefault, это вызывает AccessKeyManager.Register("\r", this) (или Unregister, если установлено значение false). (На самом деле, это немного проделывает дополнительную работу по управлению фокусом, но это, вероятно, не важно для вас.)

Итак, чтобы добиться подобного эффекта самостоятельно:

  • Создайте свойство зависимостей IsDefault обычным способом.
  • В вашем IsDefault PropertyChangedCallback вызовите AccessKeyManager.Register или AccessKeyManager.Unregister в соответствии с новым значением, передавая "\r" (строка ввода) в качестве ключа и экземпляра элемента управления как элемент.
  • Переопределить OnAccessKey , чтобы указать, как ваш элемент управления реагирует на клавишу Enter. (Например, ButtonBase переопределяет это, вызывая OnClick. Вы также можете обработать вложенное событие AccessKeyManager.AccessKeyPressed, но, поскольку вы определяете пользовательский элемент управления, переопределение OnAccessKey более аккуратно.)
0 голосов
/ 31 мая 2015

Хотя это более старый вопрос, другие могут по-прежнему интересоваться ответом, как и я. Итак, вот мое решение. Он основан на некотором обратном проектировании справочного источника Microsoft, который я нашел ( Button и ButtonBase ). Я все еще новичок в WPF, поэтому много кода может быть ненужным, но это работает!

Этот код добавляет следующие функции в UserControl (кажется, что они тесно связаны друг с другом):

  • IsDefault
  • IsCancel
  • Команда
  • Событие клика

(все комментарии в коде сделаны MS)

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.ComponentModel;
using System.Windows.Automation.Peers;
using System.Security;
using System.Diagnostics;

[DefaultEvent("Click")]
public partial class MyButton : UserControl, ICommandSource {

#region "Private Variables"

    // Cache valid bits
    private ControlBoolFlags _ControlBoolField;

#endregion

#region "Constructors"

    static MyButton() 
    {
        EventManager.RegisterClassHandler(
            typeof(MyButton), 
            AccessKeyManager.AccessKeyPressedEvent, 
            new AccessKeyPressedEventHandler(
                OnAccessKeyPressed));

        KeyboardNavigation.AcceptsReturnProperty.OverrideMetadata(
            typeof(MyButton), 
            new FrameworkPropertyMetadata(
                true));

        // Disable IME on button.
        //  - key typing should not be eaten by IME.
        //  - when the button has a focus, IME's disabled status should 
        //    be indicated as
        //    grayed buttons on the language bar.
        InputMethod.IsInputMethodEnabledProperty.OverrideMetadata(
            typeof(MyButton), 
            new FrameworkPropertyMetadata(
                false, 
                FrameworkPropertyMetadataOptions.Inherits));
    }

#endregion

#region "AccessKey"

    private static void OnAccessKeyPressed(object sender, 
        AccessKeyPressedEventArgs e)
    {
        if (!e.Handled && e.Scope == null && e.Target == null) {
            e.Target = sender as MyButton;
        }
    }

    /// <summary>
    /// The Access key for this control was invoked.
    /// </summary>
    protected override void OnAccessKey(AccessKeyEventArgs e) 
    {
        if (e.IsMultiple) {
            base.OnAccessKey(e);
        } else {
            // Don't call the base b/c we don't want to take focus
            OnClick();
        }
    }

#endregion

#region "Click"

    /// <summary>
    /// Event correspond to left mouse button click
    /// </summary>
    public static readonly RoutedEvent ClickEvent = 
        EventManager.RegisterRoutedEvent(
        "Click", 
        RoutingStrategy.Bubble, 
        typeof(RoutedEventHandler), 
        typeof(MyButton));

    /// <summary>
    /// Add / Remove ClickEvent handler
    /// </summary>
    [Category("Behavior")]
    public event RoutedEventHandler Click 
    {
        add { 
            AddHandler(ClickEvent, value); 
        }
        remove { 
            RemoveHandler(ClickEvent, value); 
        }
    }

    /// <summary>
    /// This virtual method is called when button is clicked and 
    /// it raises the Click event
    /// </summary>
    private void BaseOnClick() 
    {
        RoutedEventArgs locRoutedEventArgs = new RoutedEventArgs(
            MyButton.ClickEvent, 
            this);
        this.RaiseEvent(locRoutedEventArgs);
        ExecuteCommandSource(this);
    }

    /// <summary>
    /// This method is called when button is clicked.
    /// </summary>
    private void OnClick()
    {
        if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked)) {
            AutomationPeer locPeer = 
                UIElementAutomationPeer.CreatePeerForElement(this);
            if (locPeer != null) {
                locPeer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
            }
        }

        // base.OnClick should be called first. Our default command 
        // for Cancel Button to close dialog should happen after 
        // Button's click event handler has been called. 
        // If there Is excption And it Then 's a Cancel button and 
        // RoutedCommand is null, 
        // we will raise Window.DialogCancelCommand.
        try {
            BaseOnClick();
        } finally {
            // When the Button RoutedCommand is null, if it's a 
            // Cancel Button, 
            // Window.DialogCancelCommand will be the default command. 
            // Do not assign Window.DialogCancelCommand to 
            // Button.Command. 
            // If in Button click handler user nulls the Command, 
            // we still want to provide the default behavior.
            if (Command == null && IsCancel) {
                // Can't invoke Window.DialogCancelCommand directly. 
                // Have to raise event. 
                // Filed bug 936090: Commanding perf issue: can't 
                // directly invoke a command.
                ExecuteCommand(DialogCancelCommand, null, this);
            }
        }
    }

#endregion

#region "ClickMode"

    /// <summary>
    ///     The DependencyProperty for the ClickMode property.
    ///     Flags:              None
    ///     Default Value:      ClickMode.Release
    /// </summary>
    public static readonly DependencyProperty ClickModeProperty = 
        DependencyProperty.Register(
        "ClickMode", 
        typeof(ClickMode), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            ClickMode.Release), 
        new ValidateValueCallback(
            IsValidClickMode));

    /// <summary>
    ///     ClickMode specify when the Click event should fire
    /// </summary>
    [Bindable(true), Category("Behavior")]
    public ClickMode ClickMode 
    {
        get { 
            return (ClickMode)GetValue(ClickModeProperty); 
        }
        set { 
            SetValue(ClickModeProperty, value); 
        }
    }

    private static bool IsValidClickMode(object valClickMode)
    {
        ClickMode locClickMode = (ClickMode)valClickMode;
        return locClickMode == ClickMode.Press 
            || locClickMode == ClickMode.Release 
            || locClickMode == ClickMode.Hover;
    }

#endregion

#region "KeyDown"

    /// <summary>
    /// This is the method that responds to the KeyDown event.
    /// </summary>
    /// <param name="e">Event arguments</param>
    protected override void OnKeyDown(KeyEventArgs e) 
    {
        base.OnKeyDown(e);

        if (ClickMode == ClickMode.Hover) {
            // Ignore when in hover-click mode.
            return;
        }

        if (e.Key == Key.Space) {
            // Alt+Space should bring up system menu, we shouldn't 
            // handle it.
            if ((Keyboard.Modifiers & 
                (ModifierKeys.Control | ModifierKeys.Alt)) != 
                ModifierKeys.Alt) {
                if ((!IsMouseCaptured) && 
                    (object.ReferenceEquals(e.OriginalSource, this))) {
                    IsSpaceKeyDown = true;
                    CaptureMouse();
                    if (ClickMode == ClickMode.Press) {
                        OnClick();
                    }
                    e.Handled = true;
                }
            }
        } else if (e.Key == Key.Enter 
            && Convert.ToBoolean(GetValue(KeyboardNavigation.AcceptsReturnProperty))) {

            if (object.ReferenceEquals(e.OriginalSource, this)) {
                IsSpaceKeyDown = false;
                if (IsMouseCaptured) {
                    ReleaseMouseCapture();
                }
                OnClick();
                e.Handled = true;
            }
        } else {
            // On any other key we set IsPressed to false only if 
            // Space key is pressed
            if (IsSpaceKeyDown) {
                IsSpaceKeyDown = false;
                if (IsMouseCaptured) {
                    ReleaseMouseCapture();
                }
            }
        }
    }

    private bool IsSpaceKeyDown 
    {
        get {
            return ReadControlFlag(ControlBoolFlags.IsSpaceKeyDown); 
        }
        set { 
            WriteControlFlag(ControlBoolFlags.IsSpaceKeyDown, value); 
        }
    }

#endregion

#region "Command"

    /// <summary>
    ///     The DependencyProperty for RoutedCommand
    /// </summary>
    [CommonDependencyProperty()]
    public static readonly DependencyProperty CommandProperty = 
        DependencyProperty.Register(
        "Command", 
        typeof(ICommand), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            (ICommand)null, 
            new PropertyChangedCallback(
                OnCommandChanged)));

    /// <summary>
    /// Get or set the Command property
    /// </summary>
    [Bindable(true), Category("Action")]
    [Localizability(LocalizationCategory.NeverLocalize)]
    public ICommand Command 
    {
        get {
            return (ICommand)GetValue(CommandProperty); 
        }
        set { 
            SetValue(CommandProperty, value); 
        }
    }

    private static void OnCommandChanged(
        DependencyObject valTarget, 
        DependencyPropertyChangedEventArgs e) 
    {
        MyButton locMyButton = valTarget as MyButton;
        if (locMyButton != null) {
            locMyButton.OnCommandChanged(
                (ICommand)e.OldValue, 
                (ICommand)e.NewValue);
        }
    }

    private void OnCommandChanged(
        ICommand valOldCommand, 
        ICommand valNewCommand) 
    {
        if (valOldCommand != null) {
            valOldCommand.CanExecuteChanged -= OnCanExecuteChanged;
        }
        if (valNewCommand != null) {
            valNewCommand.CanExecuteChanged += OnCanExecuteChanged;
        }
        UpdateCanExecute();
    }

#endregion

#region "CommandParameter"

    /// <summary>
    /// The DependencyProperty for the CommandParameter
    /// </summary>
    [CommonDependencyProperty()]
    public static readonly DependencyProperty CommandParameterProperty = 
        DependencyProperty.Register(
        "CommandParameter",
        typeof(object), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            (object)null));

    /// <summary>
    /// Reflects the parameter to pass to the CommandProperty 
    /// upon execution.
    /// </summary>
    [Bindable(true), Category("Action")]
    [Localizability(LocalizationCategory.NeverLocalize)]
    public object CommandParameter 
    {
        get { 
            return GetValue(CommandParameterProperty); 
        }
        set { 
            SetValue(CommandParameterProperty, value); 
        }
    }

#endregion

#region "CommandTarget"

    /// <summary>
    ///     The DependencyProperty for Target property
    ///     Flags:              None
    ///     Default Value:      null
    /// </summary>
    [CommonDependencyProperty()]
    public static readonly DependencyProperty CommandTargetProperty = 
        DependencyProperty.Register(
        "CommandTarget", 
        typeof(IInputElement), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            (IInputElement)null));

    /// <summary>
    ///     The target element on which to fire the command.
    /// </summary>
    [Bindable(true), Category("Action")]
    public IInputElement CommandTarget 
    {
        get { 
            return (IInputElement)GetValue(CommandTargetProperty);
        }
        set { 
            SetValue(CommandTargetProperty, value); 
        }
    }

#endregion

#region "CanExecute"

    private void OnCanExecuteChanged(object valTarget, EventArgs e) 
    {
        if (valTarget != null) {
            UpdateCanExecute();
        }
    }

    private bool CanExecute 
    {
        get { 
            return !ReadControlFlag(ControlBoolFlags.CommandDisabled);
        }
        set {
            if (value != CanExecute) {
                WriteControlFlag(
                    ControlBoolFlags.CommandDisabled, 
                    !value);
                CoerceValue(IsEnabledProperty);
            }
        }
    }

    private void UpdateCanExecute() 
    {
        if (Command != null) {
            CanExecute = CanExecuteCommandSource(this);
        } else {
            CanExecute = true;
        }
    }

#endregion

#region "IsDefault"

    /// <summary>
    ///     The DependencyProperty for the IsDefault property.
    ///     Flags:              None
    ///     Default Value:      false
    /// </summary>
    public static readonly DependencyProperty IsDefaultProperty = 
        DependencyProperty.RegisterAttached(
        "IsDefault", 
        typeof(bool), 
        typeof(MyButton), 
        new UIPropertyMetadata(
            false, 
            new PropertyChangedCallback(
                OnIsDefaultChanged)));

    /// <summary>
    /// Specifies whether or not this button is the default button.
    /// </summary>
    /// <value></value>
    public bool IsDefault
    {
        get { 
            return (bool)GetValue(IsDefaultProperty); 
        } 
        set { 
            SetValue(IsDefaultProperty, value); 
        }
    }

    private static void OnIsDefaultChanged(
        DependencyObject valTarget, 
        DependencyPropertyChangedEventArgs e)
    {
        MyButton locMyButton = valTarget as MyButton;
        if (locMyButton != null) {
            Window locWindow = Window.GetWindow(locMyButton);
            if (locWindow == null) {
                locWindow = Application.Current.MainWindow;
            }
            if (FocusChangedEventHandler == null) {
                FocusChangedEventHandler = 
                    new KeyboardFocusChangedEventHandler(
                    locMyButton.OnFocusChanged);
            }

            if (locWindow != null) {
                if ((bool)e.NewValue) {
                    AccessKeyManager.Register("\x000D", locMyButton);
                    KeyboardNavigation.SetAcceptsReturn(
                        locMyButton, true);
                    locMyButton.UpdateIsDefaulted(
                        Keyboard.FocusedElement);
                } else {
                    AccessKeyManager.Unregister("\x000D", locMyButton);
                    KeyboardNavigation.SetAcceptsReturn(
                        locMyButton, false);
                    locMyButton.UpdateIsDefaulted(null);
                }
            }
        }
    }


    private static KeyboardFocusChangedEventHandler FocusChangedEventHandler;

    private void OnFocusChanged(object valTarget, KeyboardFocusChangedEventArgs e)
    {
        UpdateIsDefaulted(Keyboard.FocusedElement);
    }

#endregion

#region "IsDefaulted"

    /// <summary>
    ///     The key needed set a read-only property.
    /// </summary>
    private static readonly DependencyPropertyKey IsDefaultedPropertyKey = 
        DependencyProperty.RegisterReadOnly(
        "IsDefaulted", 
        typeof(bool), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            false));

    /// <summary>
    ///     The DependencyProperty for the IsDefaulted property.
    ///     Flags:              None
    ///     Default Value:      false
    /// </summary>
    public static readonly DependencyProperty IsDefaultedProperty =
        IsDefaultedPropertyKey.DependencyProperty;

    /// <summary>
    /// Specifies whether or not this button is the button that 
    /// would be invoked when Enter is pressed.
    /// </summary>
    /// <value></value>
    public bool IsDefaulted
    {
        get { 
            return (bool)GetValue(IsDefaultedProperty); 
        }
    }

    private void UpdateIsDefaulted(IInputElement valFocusElement)
    {
        // If it's not a default button, or nothing is focused, 
        // or it's disabled 
        // then it's not defaulted.
        if (!IsDefault || valFocusElement == null || !IsEnabled) {
            SetValue(IsDefaultedPropertyKey, false);
            return;
        }
        DependencyObject locFocusDependencyObj = 
            valFocusElement as DependencyObject;
        object locThisScope = null;
        object locFocusScope = null;

        // If the focused thing is not in this scope then 
        // IsDefaulted = false
        AccessKeyPressedEventArgs locEventArgs = 
            default(AccessKeyPressedEventArgs);

        bool locIsDefaulted = false;
        try {
            // Step 1: Determine the AccessKey scope from currently 
            // focused element
            locEventArgs = new AccessKeyPressedEventArgs();
            valFocusElement.RaiseEvent(locEventArgs);
            locFocusScope = locEventArgs.Scope;

            // Step 2: Determine the AccessKey scope from this button
            locEventArgs = new AccessKeyPressedEventArgs();
            this.RaiseEvent(locEventArgs);
            locThisScope = locEventArgs.Scope;

            // Step 3: Compare scopes
            if (object.ReferenceEquals(locThisScope, locFocusScope) 
                && (locFocusDependencyObj == null 
                || !(bool)locFocusDependencyObj.GetValue(KeyboardNavigation.AcceptsReturnProperty))) {

                locIsDefaulted = true;
            }
        } finally {
            SetValue(IsDefaultedPropertyKey, locIsDefaulted);
        }
    }

#endregion

#region "IsCancel"

    /// <summary>
    ///     The DependencyProperty for the IsCancel property.
    ///     Flags:              None
    ///     Default Value:      false
    /// </summary>
    public static readonly DependencyProperty IsCancelProperty = 
        DependencyProperty.Register(
        "IsCancel", 
        typeof(bool), 
        typeof(MyButton), 
        new FrameworkPropertyMetadata(
            false, 
            new PropertyChangedCallback(
                OnIsCancelChanged)));

    /// <summary>
    /// Specifies whether or not this button is the cancel button.
    /// </summary>
    /// <value></value>
    public bool IsCancel
    {
        get { 
            return (bool)GetValue(IsCancelProperty); 
        }
        set {
            SetValue(IsCancelProperty, value); 
        }
    }

    private static void OnIsCancelChanged(
        DependencyObject valTarget, 
        DependencyPropertyChangedEventArgs e)
    {
        MyButton locMyButton = valTarget as MyButton;
        if (locMyButton != null) {
            if ((bool)e.NewValue) {
                AccessKeyManager.Register("\x001B", locMyButton);
            } else {
                AccessKeyManager.Unregister("\x001B", locMyButton);
            }
        }
    }

#endregion

#region "Helper Functions"

    /// <summary>
    /// This allows a caller to override its ICommandSource values 
    //// (used by Button and ScrollBar)
    /// </summary>
    static internal void ExecuteCommand(
        ICommand command, 
        object parameter, 
        IInputElement target)
    {
        RoutedCommand routed = command as RoutedCommand;
        if (routed != null) {
            if (routed.CanExecute(parameter, target)) {
                routed.Execute(parameter, target);
            }
        } else if (command.CanExecute(parameter)) {
            command.Execute(parameter);
        }
    }

    static internal bool CanExecuteCommandSource(
        ICommandSource commandSource)
    {
        ICommand command = commandSource.Command;
        if (command != null) {
            object parameter = commandSource.CommandParameter;
            IInputElement target = commandSource.CommandTarget;
            RoutedCommand routed = command as RoutedCommand;
            if (routed != null) {
                if (target == null) {
                    target = commandSource as IInputElement;
                }
                return routed.CanExecute(parameter, target);
            } else {
                return command.CanExecute(parameter);
            }
        }
        return false;
    }

    /// <summary>
    ///     Executes the command on the given command source.
    /// </summary>
    /// <SecurityNote>
    ///     Critical - calls critical function (ExecuteCommandSource). 
    ///     TreatAsSafe - always passes in false for userInitiated,
    ////                  which is safe
    /// </SecurityNote>
    [SecurityCritical(), SecuritySafeCritical()]
    static internal void ExecuteCommandSource(
        ICommandSource commandSource)
    {
        CriticalExecuteCommandSource(commandSource, false);
    }

    /// <summary>
    ///     Executes the command on the given command source.
    /// </summary>
    /// <SecurityNote>
    /// Critical - sets the user initiated bit on a command, 
    ///            which is used for security purposes later. 
    ///            It is important to validate the callers of this, 
    ///            and the implementation to make sure
    ///            that we only call MarkAsUserInitiated in the 
    ///            correct cases.
    /// </SecurityNote>
    [SecurityCritical()]
    static internal void CriticalExecuteCommandSource(
        ICommandSource commandSource, 
        bool userInitiated)
    {
        ICommand command = commandSource.Command;
        if (command != null) {
            object parameter = commandSource.CommandParameter;
            IInputElement target = commandSource.CommandTarget;
            RoutedCommand routed = command as RoutedCommand;
            if (routed != null) {
                if (target == null) {
                    target = commandSource as IInputElement;
                }
                if (routed.CanExecute(parameter, target)) {
                    routed.Execute(parameter, target);
                }
            } else if (command.CanExecute(parameter)) {
                command.Execute(parameter);
            }
        }
    }

    /// <summary>
    /// DialogCancel Command. It closes window if it's dialog and return 
    /// false as the dialog value.
    /// </summary>
    /// <remarks>
    /// Right now this is only used by Cancel Button to close the dialog.
    static internal readonly RoutedCommand DialogCancelCommand = 
        new RoutedCommand(
        "DialogCancel", 
        typeof(Window));

#endregion

#region "ControlFlags"

    internal bool ReadControlFlag(ControlBoolFlags reqFlag)
    {
        return (_ControlBoolField & reqFlag) != 0;
    }

    internal void WriteControlFlag(ControlBoolFlags reqFlag, bool @set)
    {
        if (@set)
        {
            _ControlBoolField = _ControlBoolField | reqFlag;
        }
        else
        {
            _ControlBoolField = _ControlBoolField & (~reqFlag);
        }
    }

    internal enum ControlBoolFlags : ushort
    {
        ContentIsNotLogical = 0x1,
        // used in contentcontrol.cs
        IsSpaceKeyDown = 0x2,
        // used in ButtonBase.cs
        HeaderIsNotLogical = 0x4,
        // used in HeaderedContentControl.cs, HeaderedItemsControl.cs
        CommandDisabled = 0x8,
        // used in ButtonBase.cs, MenuItem.cs
        ContentIsItem = 0x10,
        // used in contentcontrol.cs
        HeaderIsItem = 0x20,
        // used in HeaderedContentControl.cs, HeaderedItemsControl.cs
        ScrollHostValid = 0x40,
        // used in ItemsControl.cs
        ContainsSelection = 0x80,
        // used in TreeViewItem.cs
        VisualStateChangeSuspended = 0x100
        // used in Control.cs
    }

#endregion
}

/// <summary>
///     An attribute that indicates that a DependencyProperty 
///     declaration is common
///     enough to be included in KnownTypes.cs.
/// </summary>
[Conditional("COMMONDPS")]
internal sealed class CommonDependencyPropertyAttribute : Attribute
{
}
...