private static void FindCommandBinding(CommandBindingCollection commandBindings, object sender, RoutedEventArgs e, ICommand command, bool execute) { int index = 0; while (true) { CommandBinding commandBinding = commandBindings.FindMatch(command, ref index); if (HandleCommandBinding(sender, e, commandBinding, execute)) { break; } } }
private static void FindCommandBinding(CommandBindingCollection commandBindings, object sender, RoutedEventArgs e, ICommand command, bool execute) { int index = 0; while (true) { CommandBinding commandBinding = commandBindings.FindMatch(command, ref index); if ((commandBinding == null) || (execute && ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, commandBinding)) || (!execute && CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, commandBinding))) { break; } } }
private static void FindCommandBinding(object sender, RoutedEventArgs e, ICommand command, bool execute) { // Check local command bindings CommandBindingCollection commandBindings = null; DependencyObject senderAsDO = sender as DependencyObject; if (InputElement.IsUIElement(senderAsDO)) { commandBindings = ((UIElement)senderAsDO).CommandBindingsInternal; } else if (InputElement.IsContentElement(senderAsDO)) { commandBindings = ((ContentElement)senderAsDO).CommandBindingsInternal; } else if (InputElement.IsUIElement3D(senderAsDO)) { commandBindings = ((UIElement3D)senderAsDO).CommandBindingsInternal; } if (commandBindings != null) { FindCommandBinding(commandBindings, sender, e, command, execute); } // If no command binding is found, check class command bindings // First find the relevant command bindings, under the lock. // Most of the time there are no such bindings; most of the rest of // the time there is only one. Lazy-allocate with this in mind. Tuple <Type, CommandBinding> tuple = null; // zero or one binding List <Tuple <Type, CommandBinding> > list = null; // more than one lock (_classCommandBindings.SyncRoot) { // Check from the current type to all the base types Type classType = sender.GetType(); while (classType != null) { CommandBindingCollection classCommandBindings = _classCommandBindings[classType] as CommandBindingCollection; if (classCommandBindings != null) { int index = 0; while (true) { CommandBinding commandBinding = classCommandBindings.FindMatch(command, ref index); if (commandBinding != null) { if (tuple == null) { tuple = new Tuple <Type, CommandBinding>(classType, commandBinding); } else { if (list == null) { list = new List <Tuple <Type, CommandBinding> >(); list.Add(tuple); } list.Add(new Tuple <Type, CommandBinding>(classType, commandBinding)); } } else { break; } } } classType = classType.BaseType; } } // execute the bindings. This can call into user code, so it must // be done outside the lock to avoid deadlock. if (list != null) { // more than one binding ExecutedRoutedEventArgs exArgs = execute ? (ExecutedRoutedEventArgs)e : null; CanExecuteRoutedEventArgs canExArgs = execute ? null : (CanExecuteRoutedEventArgs)e; for (int i = 0; i < list.Count; ++i) { // invoke the binding if ((execute && ExecuteCommandBinding(sender, exArgs, list[i].Item2)) || (!execute && CanExecuteCommandBinding(sender, canExArgs, list[i].Item2))) { // if it succeeds, advance past the remaining bindings for this type Type classType = list[i].Item1; while (++i < list.Count && list[i].Item1 == classType) { // no body needed } --i; // back up, so that the outer for-loop advances to the right place } } } else if (tuple != null) { // only one binding if (execute) { ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, tuple.Item2); } else { CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, tuple.Item2); } } }
/// <summary> /// Scans input and command bindings for matching gestures and executes the appropriate command /// </summary> /// <remarks> /// Scans for command to execute in the following order: /// - input bindings associated with the targetElement instance /// - input bindings associated with the targetElement class /// - command bindings associated with the targetElement instance /// - command bindings associated with the targetElement class /// </remarks> /// <param name="targetElement">UIElement/ContentElement to be scanned for input and command bindings</param> /// <param name="inputEventArgs">InputEventArgs to be matched against for gestures</param> internal static void TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs) { if ((targetElement == null) || (inputEventArgs == null)) { return; } ICommand command = null; IInputElement target = null; object parameter = null; // Determine UIElement/ContentElement/Neither type DependencyObject targetElementAsDO = targetElement as DependencyObject; bool isUIElement = InputElement.IsUIElement(targetElementAsDO); bool isContentElement = !isUIElement && InputElement.IsContentElement(targetElementAsDO); bool isUIElement3D = !isUIElement && !isContentElement && InputElement.IsUIElement3D(targetElementAsDO); // Step 1: Check local input bindings InputBindingCollection localInputBindings = null; if (isUIElement) { localInputBindings = ((UIElement)targetElement).InputBindingsInternal; } else if (isContentElement) { localInputBindings = ((ContentElement)targetElement).InputBindingsInternal; } else if (isUIElement3D) { localInputBindings = ((UIElement3D)targetElement).InputBindingsInternal; } if (localInputBindings != null) { InputBinding inputBinding = localInputBindings.FindMatch(targetElement, inputEventArgs); if (inputBinding != null) { command = inputBinding.Command; target = inputBinding.CommandTarget; parameter = inputBinding.CommandParameter; } } // Step 2: If no command, check class input bindings if (command == null) { lock (_classInputBindings.SyncRoot) { Type classType = targetElement.GetType(); while (classType != null) { InputBindingCollection classInputBindings = _classInputBindings[classType] as InputBindingCollection; if (classInputBindings != null) { InputBinding inputBinding = classInputBindings.FindMatch(targetElement, inputEventArgs); if (inputBinding != null) { command = inputBinding.Command; target = inputBinding.CommandTarget; parameter = inputBinding.CommandParameter; break; } } classType = classType.BaseType; } } } // Step 3: If no command, check local command bindings if (command == null) { // Check for the instance level ones Next CommandBindingCollection localCommandBindings = null; if (isUIElement) { localCommandBindings = ((UIElement)targetElement).CommandBindingsInternal; } else if (isContentElement) { localCommandBindings = ((ContentElement)targetElement).CommandBindingsInternal; } else if (isUIElement3D) { localCommandBindings = ((UIElement3D)targetElement).CommandBindingsInternal; } if (localCommandBindings != null) { command = localCommandBindings.FindMatch(targetElement, inputEventArgs); } } // Step 4: If no command, look at class command bindings if (command == null) { lock (_classCommandBindings.SyncRoot) { Type classType = targetElement.GetType(); while (classType != null) { CommandBindingCollection classCommandBindings = _classCommandBindings[classType] as CommandBindingCollection; if (classCommandBindings != null) { command = classCommandBindings.FindMatch(targetElement, inputEventArgs); if (command != null) { break; } } classType = classType.BaseType; } } } // Step 5: If found a command, then execute it (unless it is // the special "NotACommand" command, which we simply ignore without // setting Handled=true, so that the input bubbles up to the parent) if (command != null && command != ApplicationCommands.NotACommand) { // We currently do not support declaring the element with focus as the target // element by setting target == null. Instead, we interpret a null target to indicate // the element that we are routing the event through, e.g. the targetElement parameter. if (target == null) { target = targetElement; } bool continueRouting = false; RoutedCommand routedCommand = command as RoutedCommand; if (routedCommand != null) { if (routedCommand.CriticalCanExecute(parameter, target, inputEventArgs.UserInitiated /*trusted*/, out continueRouting)) { // If the command can be executed, we never continue to route the // input event. continueRouting = false; ExecuteCommand(routedCommand, parameter, target, inputEventArgs); } } else { if (command.CanExecute(parameter)) { command.Execute(parameter); } } // If we mapped an input event to a command, we should always // handle the input event - regardless of whether the command // was executed or not. Unless the CanExecute handler told us // to continue the route. inputEventArgs.Handled = !continueRouting; } }
private static void FindCommandBinding(CommandBindingCollection commandBindings, object sender, RoutedEventArgs e, ICommand command, bool execute) { int index = 0; while (true) { CommandBinding commandBinding = commandBindings.FindMatch(command, ref index); if ((commandBinding == null) || (execute && ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, commandBinding)) || (!execute && CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, commandBinding))) { break; } } }