File: Core\CSharp\System\Windows\Input\Command\InputBinding.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//---------------------------------------------------------------------------
 
using System;
using System.Security;              // SecurityCritical, TreatAsSafe
using System.Security.Permissions;
using System.Windows;
using System.Windows.Markup;
using System.ComponentModel;
 
using MS.Internal;
using MS.Internal.PresentationCore;
 
 
namespace System.Windows.Input 
{
    /// <summary>
    /// InputBinding - InputGesture and ICommand combination
    ///                Used to specify the binding between Gesture and Command at Element level.
    /// </summary>
    public class InputBinding : Freezable, ICommandSource
    {
#region Constructor
 
        /// <summary>
        ///     Default Constructor - needed to allow markup creation
        /// </summary>
        protected InputBinding()
        {
        }
 
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="command">Command</param>
        /// <param name="gesture">Input Gesture</param>
        /// <SecurityNote>
        /// Critical - may associate a secure command with a gesture, in 
        ///            these cases we need to demand the appropriate permission.
        /// TreatAsSafe - Calls CheckSecureCommand which does the appropriate demand.
        /// </SecurityNote>
        [SecurityCritical]
        public InputBinding(ICommand command, InputGesture gesture) 
        {   
            if (command == null)
                throw new ArgumentNullException("command");
 
            if (gesture == null)
                throw new ArgumentNullException("gesture");
 
            // Check before assignment to avoid continuation
            CheckSecureCommand(command, gesture);
 
            Command = command;
            _gesture = gesture;
        }
 
#endregion Constructor
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
#region Public Methods       
 
        /// <summary>
        ///     Dependency Property for Command property
        /// </summary>
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(InputBinding), new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandPropertyChanged)));
 
        /// <summary>
        /// Command Object associated
        /// </summary>
        /// <SecurityNote>
        /// Critical - may associate a secure command with a gesture, in 
        ///            these cases we need to demand the appropriate permission.
        /// PublicOk - Calls CheckSecureCommand which does the appropriate demand.
        /// </SecurityNote>
        [TypeConverter("System.Windows.Input.CommandConverter, PresentationFramework, Version=" + BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
        [Localizability(LocalizationCategory.NeverLocalize)] // cannot be localized
        public ICommand Command
        {
            get     
            {
                return (ICommand)GetValue(CommandProperty);
            }
            set
            {
                SetValue(CommandProperty, value);
            }
        }
 
        /// <summary>
        ///     Property changed callback for Command property
        /// </summary>
        /// <SecurityNote>
        /// Critical - may associate a secure command with a gesture, in 
        ///            these cases we need to demand the appropriate permission.
        /// TreatAsSafe - Calls CheckSecureCommand which does the appropriate demand.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        private static void OnCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            InputBinding inputBinding = (InputBinding)d;
            inputBinding.CheckSecureCommand((ICommand)e.NewValue, inputBinding.Gesture);
        }
 
        /// <summary>
        ///     Dependency Property for Command Parameter
        /// </summary>
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(InputBinding));
 
        /// <summary>
        ///     A parameter for the command.
        /// </summary>
        public object CommandParameter
        {
            get
            {
                return GetValue(CommandParameterProperty);
            }
            set
            {
                SetValue(CommandParameterProperty, value);
            }
        }
 
        /// <summary>
        ///     Dependency property for command target
        /// </summary>
        public static readonly DependencyProperty CommandTargetProperty =
            DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(InputBinding));
 
        /// <summary>
        ///     Where the command should be raised.
        /// </summary>
        public IInputElement CommandTarget
        {
            get
            {
                return (IInputElement)GetValue(CommandTargetProperty);
            }
            set
            {
                SetValue(CommandTargetProperty, value);
            }
        }
 
        /// <summary>
        /// InputGesture associated with the Command
        /// </summary>
        /// <SecurityNote>
        /// Critical - may associate a secure command with a gesture, in 
        ///            these cases we need to demand the appropriate permission.
        /// PublicOk - Calls CheckSecureCommand which does the appropriate demand.
        /// </SecurityNote>
        public virtual InputGesture Gesture
        {
            // We would like to make this getter non-virtual but that's not legal
            // in C#.  Luckily there is no security issue with leaving it virtual.
            get
            {
                ReadPreamble();
                return _gesture;
            }
            
            [SecurityCritical]
            set
            {
                WritePreamble();
                if (value == null)
                    throw new ArgumentNullException("value");
 
                lock (_dataLock)
                {
                    // Check before assignment to avoid continuation
                    //
                    CheckSecureCommand(Command, value);
 
                    _gesture = value;
                }
                WritePostscript();
            }
        }
#endregion Public Methods
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        /// <SecurityNote>
        /// Critical - determines if a command will later make an
        ///            assert. This is critical to be right, because
        ///            later we assume that the binding was protected.
        /// TreatAsSafe - Demand() is not an unsafe operation
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        void CheckSecureCommand(ICommand command, InputGesture gesture)
        {
            // In v3.5, only ApplicationCommands.Paste was treated as ISecureCommand,
            // causing the below demand to fail if a binding for it was created. As
            // there's no provable security vulnerability and for backwards compat
            // reasons, we special-case Cut and Copy not to be subject to this check
            // even though they have been promoted to ISecureCommand in v4.0.
            //
            // See Dev10 bug 815844 on reevaluating the threat model around protection
            // of key bindings. The following demand may be unnecessary or misguided.
            ISecureCommand secure = command as ISecureCommand;
            if (   secure != null
                && command != ApplicationCommands.Cut
                && command != ApplicationCommands.Copy)
            {
                secure.UserInitiatedPermission.Demand();
            }
        }
 
        #region Freezable
 
        /// <summary>
        ///     Freezable override to create the instance (used for cloning).
        /// </summary>
        protected override Freezable CreateInstanceCore()
        {
            return new InputBinding();
        }
 
        /// <summary>
        ///     Freezable override to clone the non dependency properties
        /// </summary>
        protected override void CloneCore(Freezable sourceFreezable)
        {
            base.CloneCore(sourceFreezable);
            _gesture = ((InputBinding)sourceFreezable).Gesture;
        }
 
        /// <summary>
        ///     Freezable override to clone the non dependency properties
        /// </summary>
        protected override void CloneCurrentValueCore(Freezable sourceFreezable)
        {
            base.CloneCurrentValueCore(sourceFreezable);
            _gesture = ((InputBinding)sourceFreezable).Gesture;
        }
 
        /// <summary>
        ///     Freezable override of GetAsFrozenCore
        /// </summary>
        protected override void GetAsFrozenCore(Freezable sourceFreezable)
        {
            base.GetAsFrozenCore(sourceFreezable);
            _gesture = ((InputBinding)sourceFreezable).Gesture;
        }
 
        /// <summary>
        ///     Freezable override of GetCurrentValueAsFrozenCore
        /// </summary>
        protected override void GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
        {
            base.GetCurrentValueAsFrozenCore(sourceFreezable);
            _gesture = ((InputBinding)sourceFreezable).Gesture;
        }
 
        #endregion
 
        #region Inheirtance context
 
        /// <summary>
        ///     Define the DO's inheritance context
        /// </summary>
        internal override DependencyObject InheritanceContext
        {
            get { return _inheritanceContext; }
        }
 
        /// <summary>
        ///     Receive a new inheritance context
        /// </summary>
        internal override void AddInheritanceContext(DependencyObject context, DependencyProperty property)
        {
            InheritanceContextHelper.AddInheritanceContext(context,
                                                           this,
                                                           ref _hasMultipleInheritanceContexts,
                                                           ref _inheritanceContext);
        }
 
        /// <summary>
        ///     Remove an inheritance context
        /// </summary>
        internal override void RemoveInheritanceContext(DependencyObject context, DependencyProperty property)
        {
            InheritanceContextHelper.RemoveInheritanceContext(context,
                                                              this,
                                                              ref _hasMultipleInheritanceContexts,
                                                              ref _inheritanceContext);
        }
 
        /// <summary>
        ///     Says if the current instance has multiple InheritanceContexts
        /// </summary>
        internal override bool HasMultipleInheritanceContexts
        {
            get { return _hasMultipleInheritanceContexts; }
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
#region Private Fields
        private     InputGesture  _gesture = null ;
 
        internal static object _dataLock = new object();
 
        // Fields to implement DO's inheritance context
        private DependencyObject _inheritanceContext = null;
        private bool _hasMultipleInheritanceContexts = false;
#endregion Private Fields
    }
}