未验证 提交 fdc7654f 编写于 作者: R Robin Lindner 提交者: GitHub

FindCommandBinding improvements (#5693)

* General code improvements for CommandManager.FindCommandBinding

* Further improvements
上级 ba2b1840
......@@ -7,6 +7,7 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Markup;
using MS.Internal;
......@@ -60,18 +61,13 @@ public CommandBinding(ICommand command, ExecutedRoutedEventHandler executed)
/// <param name="canExecute">Handler associated with determining if the command can execute.</param>
public CommandBinding(ICommand command, ExecutedRoutedEventHandler executed, CanExecuteRoutedEventHandler canExecute)
{
if (command == null)
{
throw new ArgumentNullException("command");
}
_command = command ?? throw new ArgumentNullException(nameof(command));
_command = command;
if (executed != null)
if (executed is not null)
{
Executed += executed;
}
if (canExecute != null)
if (canExecute is not null)
{
CanExecute += canExecute;
}
......@@ -87,20 +83,8 @@ public CommandBinding(ICommand command, ExecutedRoutedEventHandler executed, Can
[Localizability(LocalizationCategory.NeverLocalize)] // cannot be localized
public ICommand Command
{
get
{
return _command;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
_command = value;
}
get => _command;
set => _command = value ?? throw new ArgumentNullException(nameof(value));
}
#endregion
......@@ -138,49 +122,46 @@ public ICommand Command
/// <param name="e">Event arguments.</param>
internal void OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
if (!e.Handled)
if (e.Handled) return;
if (e.RoutedEvent == CommandManager.CanExecuteEvent)
{
if (e.RoutedEvent == CommandManager.CanExecuteEvent)
if (CanExecute is null)
{
if (CanExecute != null)
{
CanExecute(sender, e);
if (e.CanExecute)
{
e.Handled = true;
}
}
else if (!e.CanExecute)
{
// If there is an Executed handler, then the command can be executed.
if (Executed != null)
{
e.CanExecute = true;
e.Handled = true;
}
}
if (e.CanExecute) return;
// If there is an Executed handler, then the command can be executed.
if (Executed is null) return;
e.CanExecute = true;
e.Handled = true;
}
else // e.RoutedEvent == CommandManager.PreviewCanExecuteEvent
else
{
if (PreviewCanExecute != null)
CanExecute(sender, e);
if (e.CanExecute)
{
PreviewCanExecute(sender, e);
if (e.CanExecute)
{
e.Handled = true;
}
e.Handled = true;
}
}
}
else // e.RoutedEvent == CommandManager.PreviewCanExecuteEvent
{
if (PreviewCanExecute is null) return;
PreviewCanExecute(sender, e);
if (e.CanExecute)
{
e.Handled = true;
}
}
}
private bool CheckCanExecute(object sender, ExecutedRoutedEventArgs e)
{
CanExecuteRoutedEventArgs canExecuteArgs = new CanExecuteRoutedEventArgs(e.Command, e.Parameter);
canExecuteArgs.RoutedEvent = CommandManager.CanExecuteEvent;
CanExecuteRoutedEventArgs canExecuteArgs = new(e.Command, e.Parameter)
{
RoutedEvent = CommandManager.CanExecuteEvent,
// Since we don't actually raise this event, we have to explicitly set the source.
Source = e.OriginalSource
};
// Since we don't actually raise this event, we have to explicitly set the source.
canExecuteArgs.Source = e.OriginalSource;
canExecuteArgs.OverrideSource(e.Source);
OnCanExecute(sender, canExecuteArgs);
......@@ -195,30 +176,22 @@ private bool CheckCanExecute(object sender, ExecutedRoutedEventArgs e)
/// <param name="e">Event arguments.</param>
internal void OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
if (!e.Handled)
if (e.Handled) return;
if (e.RoutedEvent == CommandManager.ExecutedEvent)
{
if (e.RoutedEvent == CommandManager.ExecutedEvent)
{
if (Executed != null)
{
if (CheckCanExecute(sender, e))
{
Executed(sender, e);
e.Handled = true;
}
}
}
else // e.RoutedEvent == CommandManager.PreviewExecutedEvent
{
if (PreviewExecuted != null)
{
if (CheckCanExecute(sender, e))
{
PreviewExecuted(sender, e);
e.Handled = true;
}
}
}
if (Executed is null) return;
if (!CheckCanExecute(sender, e)) return;
Debug.Assert(Executed != null, nameof(Executed) + " != null");
Executed(sender, e);
e.Handled = true;
}
else // e.RoutedEvent == CommandManager.PreviewExecutedEvent
{
if (PreviewExecuted is null) return;
if (!CheckCanExecute(sender, e)) return;
Debug.Assert(PreviewExecuted != null, nameof(PreviewExecuted) + " != null");
PreviewExecuted(sender, e);
e.Handled = true;
}
}
......
......@@ -52,9 +52,9 @@ public CommandBindingCollection()
/// <param name="commandBindings">CommandBinding array</param>
public CommandBindingCollection(IList commandBindings)
{
if (commandBindings != null && commandBindings.Count > 0)
if (commandBindings is { Count: > 0 })
{
AddRange(commandBindings as ICollection);
AddRange(commandBindings);
}
}
......@@ -76,12 +76,9 @@ public CommandBindingCollection(IList commandBindings)
/// </summary>
/// <param name="array">commandbinding array to copy into</param>
/// <param name="index">start index in current list to copy</param>
void ICollection.CopyTo(System.Array array, int index)
void ICollection.CopyTo(System.Array array, int index)
{
if (_innerCBList != null)
{
((ICollection)_innerCBList).CopyTo(array, index);
}
((ICollection)_innerCBList)?.CopyTo(array, index);
}
#endregion Implementation of ICollection
......@@ -92,7 +89,7 @@ void ICollection.CopyTo(System.Array array, int index)
/// <returns>true - if found, false - otherwise</returns>
bool IList.Contains(object key)
{
return this.Contains(key as CommandBinding) ;
return Contains(key as CommandBinding) ;
}
/// <summary>
......@@ -102,8 +99,7 @@ bool IList.Contains(object key)
/// <returns></returns>
int IList.IndexOf(object value)
{
CommandBinding commandBinding = value as CommandBinding;
return ((commandBinding != null) ? this.IndexOf(commandBinding) : -1);
return ((value is CommandBinding commandBinding) ? IndexOf(commandBinding) : -1);
}
/// <summary>
......@@ -113,7 +109,7 @@ int IList.IndexOf(object value)
/// <param name="value">item to insert</param>
void IList.Insert(int index, object value)
{
this.Insert(index, value as CommandBinding);
Insert(index, value as CommandBinding);
}
/// <summary>
......@@ -122,7 +118,7 @@ void IList.Insert(int index, object value)
/// <param name="commandBinding">CommandBinding object to add</param>
int IList.Add(object commandBinding)
{
return this.Add(commandBinding as CommandBinding);
return Add(commandBinding as CommandBinding);
}
/// <summary>
......@@ -131,7 +127,7 @@ int IList.Add(object commandBinding)
/// <param name="commandBinding">CommandBinding object to remove</param>
void IList.Remove(object commandBinding)
{
this.Remove(commandBinding as CommandBinding);
Remove(commandBinding as CommandBinding);
}
/// <summary>
......@@ -145,8 +141,7 @@ void IList.Remove(object commandBinding)
}
set
{
CommandBinding commandBinding = value as CommandBinding;
if (commandBinding == null)
if (value is not CommandBinding commandBinding)
throw new NotSupportedException(SR.Get(SRID.CollectionOnlyAcceptsCommandBindings));
this[index] = commandBinding;
......@@ -160,7 +155,7 @@ void IList.Remove(object commandBinding)
{
get
{
return (_innerCBList != null ? _innerCBList[index] : null);
return (_innerCBList?[index]);
}
set
{
......@@ -179,8 +174,7 @@ public int Add(CommandBinding commandBinding)
{
if (commandBinding != null)
{
if (_innerCBList == null)
_innerCBList = new System.Collections.Generic.List<CommandBinding>(1);
_innerCBList ??= new Collections.Generic.List<CommandBinding>(1);
_innerCBList.Add(commandBinding);
return 0; // ICollection.Add no longer returns the indice
......@@ -200,27 +194,23 @@ public int Add(CommandBinding commandBinding)
public void AddRange(ICollection collection)
{
if (collection==null)
throw new ArgumentNullException("collection");
if (collection.Count > 0)
{
if (_innerCBList == null)
_innerCBList = new System.Collections.Generic.List<CommandBinding>(collection.Count);
throw new ArgumentNullException(nameof(collection));
if (collection.Count <= 0) return;
_innerCBList ??= new System.Collections.Generic.List<CommandBinding>(collection.Count);
IEnumerator collectionEnum = collection.GetEnumerator();
while(collectionEnum.MoveNext())
IEnumerator collectionEnum = collection.GetEnumerator();
while(collectionEnum.MoveNext())
{
if (collectionEnum.Current is CommandBinding cmdBinding)
{
CommandBinding cmdBinding = collectionEnum.Current as CommandBinding;
if (cmdBinding != null)
{
_innerCBList.Add(cmdBinding);
}
else
{
throw new NotSupportedException(SR.Get(SRID.CollectionOnlyAcceptsCommandBindings));
}
}
}
_innerCBList.Add(cmdBinding);
}
else
{
throw new NotSupportedException(SR.Get(SRID.CollectionOnlyAcceptsCommandBindings));
}
}
}
/// <summary>
......@@ -232,8 +222,7 @@ public void Insert(int index, CommandBinding commandBinding)
{
if (commandBinding != null)
{
if (_innerCBList != null)
_innerCBList.Insert(index, commandBinding);
_innerCBList?.Insert(index, commandBinding);
}
else
{
......@@ -257,8 +246,7 @@ public void Remove(CommandBinding commandBinding)
/// <param name="index">index at which the item needs to be removed</param>
public void RemoveAt(int index)
{
if (_innerCBList != null)
_innerCBList.RemoveAt(index);
_innerCBList?.RemoveAt(index);
}
/// <summary>
......@@ -276,11 +264,7 @@ public bool IsSynchronized
{
get
{
if (_innerCBList != null)
{
return ((IList)_innerCBList).IsSynchronized;
}
return false;
return _innerCBList is not null && ((IList)_innerCBList).IsSynchronized;
}
}
......@@ -310,7 +294,7 @@ public int Count
{
get
{
return (_innerCBList != null ? _innerCBList.Count : 0);
return _innerCBList?.Count ?? 0;
}
}
......@@ -319,11 +303,9 @@ public int Count
/// </summary>
public void Clear()
{
if (_innerCBList != null)
{
_innerCBList.Clear();
_innerCBList = null;
}
if (_innerCBList is null) return;
_innerCBList.Clear();
_innerCBList = null;
}
/// <summary>
......@@ -333,7 +315,7 @@ public void Clear()
/// <returns></returns>
public int IndexOf(CommandBinding value)
{
return ((_innerCBList != null) ? _innerCBList.IndexOf(value) : -1);
return _innerCBList?.IndexOf(value) ?? -1;
}
/// <summary>
......@@ -355,10 +337,9 @@ public bool Contains(CommandBinding commandBinding)
/// </summary>
/// <param name="commandBindings"> type-safe (CommandBinding) array</param>
/// <param name="index">start index in current list to copy</param>
public void CopyTo(CommandBinding[] commandBindings, int index)
public void CopyTo(CommandBinding[] commandBindings, int index)
{
if (_innerCBList != null)
_innerCBList.CopyTo(commandBindings, index);
_innerCBList?.CopyTo(commandBindings, index);
}
#region Implementation of Enumerable
......@@ -385,17 +366,11 @@ internal ICommand FindMatch(object targetElement, InputEventArgs inputEventArgs)
for (int i = 0; i < Count; i++)
{
CommandBinding commandBinding = this[i];
RoutedCommand routedCommand = commandBinding.Command as RoutedCommand;
if (routedCommand != null)
if (commandBinding.Command is not RoutedCommand routedCommand) continue;
InputGestureCollection inputGestures = routedCommand.InputGesturesInternal;
if (inputGestures?.FindMatch(targetElement, inputEventArgs) != null)
{
InputGestureCollection inputGestures = routedCommand.InputGesturesInternal;
if (inputGestures != null)
{
if (inputGestures.FindMatch(targetElement, inputEventArgs) != null)
{
return routedCommand;
}
}
return routedCommand;
}
}
......@@ -423,7 +398,7 @@ internal CommandBinding FindMatch(ICommand command, ref int index)
//
//------------------------------------------------------
#region Private Fields
private System.Collections.Generic.List<CommandBinding> _innerCBList;
private Collections.Generic.List<CommandBinding> _innerCBList;
#endregion Private Fields
}
}
......@@ -599,64 +599,56 @@ internal static void OnCommandDevice(object sender, CommandDeviceEventArgs e)
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))
CommandBindingCollection commandBindings = sender switch
{
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)
UIElement uiElement => uiElement.CommandBindingsInternal,
ContentElement contentElement => contentElement.CommandBindingsInternal,
UIElement3D uiElement3d => uiElement3d.CommandBindingsInternal,
_ => default
};
if (commandBindings is not null)
{
FindCommandBinding(commandBindings, sender, e, command, execute);
}
Type senderType = sender.GetType();
// 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
ValueTuple<Type, CommandBinding>? tuple = default; // zero or one binding
List<ValueTuple<Type, CommandBinding>> list = default; // more than one
lock (_classCommandBindings.SyncRoot)
{
// Check from the current type to all the base types
Type classType = sender.GetType();
while (classType != null)
Type classType = senderType;
while (classType is not null)
{
CommandBindingCollection classCommandBindings = _classCommandBindings[classType] as CommandBindingCollection;
if (classCommandBindings != null)
if (_classCommandBindings[classType] is CommandBindingCollection classCommandBindings)
{
int index = 0;
while (true)
{
CommandBinding commandBinding = classCommandBindings.FindMatch(command, ref index);
if (commandBinding != null)
if (commandBinding is 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));
}
break;
}
if (tuple is null)
{
tuple = ValueTuple.Create(classType, commandBinding);
}
else
{
break;
list ??= new List<ValueTuple<Type, CommandBinding>>(8)
{
// We know that tuple cannot be null here
tuple.Value
};
list.Add(new ValueTuple<Type, CommandBinding>(classType, commandBinding));
}
}
}
......@@ -666,37 +658,35 @@ private static void FindCommandBinding(object sender, RoutedEventArgs e, IComman
// execute the bindings. This can call into user code, so it must
// be done outside the lock to avoid deadlock.
if (list != null)
if (list is not 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)
ExecutedRoutedEventArgs exArgs = execute ? (ExecutedRoutedEventArgs)e : default;
CanExecuteRoutedEventArgs canExArgs = execute ? default : (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 ((!execute || !ExecuteCommandBinding(sender, exArgs, list[i].Item2)) &&
(execute || !CanExecuteCommandBinding(sender, canExArgs, list[i].Item2))) continue;
// if it succeeds, advance past the remaining bindings for this type
Type classType = list[i].Item1;
while (++i < list.Count && list[i].Item1 == classType)
{
// 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
// no body needed
}
--i; // back up, so that the outer for-loop advances to the right place
}
}
else if (tuple != null)
else if (tuple is var (_, commandBinding))
{
// only one binding
if (execute)
{
ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, tuple.Item2);
ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, commandBinding);
}
else
{
CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, tuple.Item2);
CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, commandBinding);
}
}
}
......@@ -707,15 +697,20 @@ private static void FindCommandBinding(CommandBindingCollection commandBindings,
while (true)
{
CommandBinding commandBinding = commandBindings.FindMatch(command, ref index);
if ((commandBinding == null) ||
(execute && ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, commandBinding)) ||
(!execute && CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, commandBinding)))
if (HandleCommandBinding(sender, e, commandBinding, execute))
{
break;
}
}
}
private static bool HandleCommandBinding(object sender, RoutedEventArgs e, CommandBinding commandBinding, bool execute)
{
return commandBinding is null ||
execute && ExecuteCommandBinding(sender, (ExecutedRoutedEventArgs)e, commandBinding) ||
!execute && CanExecuteCommandBinding(sender, (CanExecuteRoutedEventArgs)e, commandBinding);
}
private static void TransferEvent(IInputElement newSource, CanExecuteRoutedEventArgs e)
{
RoutedCommand command = e.Command as RoutedCommand;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册