开发者

Can a custom WPF control implement the IsDefault property

I have a custom button control that does not derive from Button. Is it possible for me to implement the equivalent of IsDefault so that the command associated with my control will be invoked. I was hoping that this was an attached property that I could add to any control but as far as I can tell it doesn't seem to be. Am I out of luck if my control does not derive from Button or is there at least a reasonable workaround?

UPDATE: I just took a peek with reflector at how this is being done underneath for Button and I must say it isn't the most self explanitory code I've seen. It appears that there are at least 3 dependency properties a few custom types just for the purpose of handling the concept of a Button being default. Since there doesn't seem to be an existing way to borrow the IsDefault functionality I suppose I'll have to narrow down what I'm trying to achieve so that I can at least get default focus and access key handling to work and just ignore the complexity invloved in the Button.IsDefault implementation.

UPDATE: Added the following code example showing my uncessful attempt at trying itowlson's suggestions.

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"
                                   Horizo开发者_运维问答ntalAlignment="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!");
        }
    }
}


All that setting Button.IsDefault does is call AccessKeyManager.Register("\r", this) (or Unregister if setting to false). (Actually, it does a little bit of extra work around focus management, but that's probably not crucial for you.)

So to achieve a similar effect yourself:

  • Create an IsDefault dependency property in the usual way.
  • In your IsDefault PropertyChangedCallback, call AccessKeyManager.Register or AccessKeyManager.Unregister according to the new value, passing "\r" (the Enter string) as the key and the control instance as the element.
  • Override OnAccessKey to specify how your control responds to the Enter key. (For example, ButtonBase overrides this to call OnClick. You could also handle the AccessKeyManager.AccessKeyPressed attached event, but since you are defining a custom control, overriding OnAccessKey is neater.)


Although this is an older question others may still be interested in an answer as I have been. So, here is my solution. It's based on some reverse engineering of Microsoft reference source I've found (Button and ButtonBase). I'm still newby in WPF so much code may be needless, but it works!

This code adds following features to an UserControl (they seem to be closly connected to each other):

  • IsDefault
  • IsCancel
  • Command
  • Click event

(all comments in code are made by 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
{
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜