自定义WPF控件是否可以实现IsDefault属性

时间:2010-04-13 23:26:35

标签: wpf button custom-controls defaultbutton

我有一个不是从Button派生的自定义按钮控件。我是否可以实现等效的 IsDefault ,以便调用与我的控件关联的命令。我希望这是一个附加属性,我可以添加到任何控件,但据我所知,它似乎不是。如果我的控件不是从Button派生的,或者至少是否有合理的解决方法,我是不是运气不好?

更新 我只是偷看了反射器,看看它是如何在Button下进行的,我必须说它不是我见过的最自我解释的代码。看来,为了处理Button默认的概念,至少有3个自定义类型的自定义类型。由于似乎没有现成的借用IsDefault功能的方法,我想我必须缩小我想要实现的目标,这样我至少可以获得默认焦点和访问键处理工作而忽略Button.IsDefault实现中隐藏的复杂性。

更新 添加了以下代码示例,显示了我尝试 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 个答案:

答案 0 :(得分:5)

Button.IsDefault的所有设置都是调用AccessKeyManager.Register("\r", this)(如果设置为false,则取消注册)。 (实际上,它在焦点管理方面做了一些额外的工作,但这对你来说可能并不重要。)

所以要自己实现类似的效果:

  • 以通常的方式创建IsDefault依赖项属性。
  • 在IsDefault PropertyChangedCallback中,根据新值调用AccessKeyManager.RegisterAccessKeyManager.Unregister,将"\r"(输入字符串)作为键,控制实例作为元素。
  • 覆盖OnAccessKey以指定控件如何响应Enter键。 (例如,ButtonBase会覆盖它以调用OnClick。您也可以处理AccessKeyManager.AccessKeyPressed附加事件,但由于您正在定义自定义控件,因此覆盖OnAccessKey更整洁。)

答案 1 :(得分:0)

虽然这是一个较老的问题,但其他人可能仍然对我的答案感兴趣。所以,这是我的解决方案。它基于我发现的Microsoft参考源的一些逆向工程(ButtonButtonBase)。我仍然在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
{
}