4

Buttonから派生していないカスタムボタンコントロールがあります。コントロールに関連付けられたコマンドが呼び出されるように、IsDefaultと同等の機能を実装することはできますか?これが任意のコントロールに追加できる添付プロパティであることを期待していましたが、私が知る限り、そうではないようです。私のコントロールがボタンから派生していない場合、または少なくとも合理的な回避策がある場合、私は運が悪いですか?

更新: ボタンの下でこれがどのように行われているのかをリフレクターで覗いてみましたが、これは私が見た中で最も自明なコードではないと言わざるを得ません。ボタンがデフォルトであるという概念を処理するためだけに、少なくとも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!");
        }
    }
}
4

2 に答える 2

5

その設定 Button.IsDefault が行うのは、呼び出しAccessKeyManager.Register("\r", this)(または false に設定する場合は登録解除) だけです。(実際には、フォーカス管理に関して少し余分な作業を行いますが、それはおそらく重要ではありません。)

したがって、同様の効果を自分で達成するには:

  • 通常の方法で IsDefault 依存関係プロパティを作成します。
  • IsDefault PropertyChangedCallback で、新しい値に従ってAccessKeyManager.RegisterまたはAccessKeyManager.Unregister"\r"を呼び出し、 (Enter 文字列) をキーとして、コントロール インスタンスを要素として渡します。
  • OnAccessKeyをオーバーライドして、コントロールが Enter キーにどのように応答するかを指定します。(たとえば、ButtonBase はこれをオーバーライドして OnClick を呼び出します。AccessKeyManager.AccessKeyPressed 添付イベントを処理することもできますが、カスタム コントロールを定義しているため、OnAccessKey をオーバーライドする方が適切です。)
于 2010-04-14T01:56:04.140 に答える
0

これは古い質問ですが、私がそうであったように、他の人はまだ答えに興味があるかもしれません. だから、ここに私の解決策があります。これは、私が見つけた 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
{
}
于 2015-05-31T15:39:42.330 に答える