从 wpf 中的文本框禁用快捷命令,保持击键检测
disable shortcut commands from textbox in wpf, keeping keystrokes detection
我正在尝试一种从 WPF 应用程序中的文本框捕获组合键的方法。
到目前为止编写的代码(我在其他讨论中找到的)帮助我做到这一点,除了那些链接到快捷命令的组合(Ctrl+C、Ctrl+V、Ctrl+X...)。
我想捕获用户在文本框上按下的所有键(Space、Delete、Backspace 和上面的所有组合)。
这是代码:
int MaxKeyCount = 3;
List<Key> PressedKeys = new List<Key>();
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Handled) return;
//Check all previous keys to see if they are still pressed
List<Key> KeysToRemove = new List<Key>();
foreach (Key k in PressedKeys)
{
if (!Keyboard.IsKeyDown(k))
KeysToRemove.Add(k);
}
//Remove all not pressed keys
foreach (Key k in KeysToRemove)
PressedKeys.Remove(k);
//Add the key if max count is not reached
if (PressedKeys.Count < MaxKeyCount)
//Add the key if it is part of the allowed keys
//if (AllowedKeys.Contains(e.Key))
if (!PressedKeys.Contains(e.Key))
PressedKeys.Add(e.Key);
PrintKeys();
e.Handled = true;
}
private void PrintKeys()
{
//Print all pressed keys
string s = "";
if (PressedKeys.Count == 0) return;
foreach (Key k in PressedKeys)
if (IsModifierKey(k))
s += GetModifierKey(k) + " + ";
else
s += k + " + ";
s = s.Substring(0, s.Length - 3);
TextBox.Text = s;
}
private bool IsModifierKey(Key k)
{
if (k == Key.LeftCtrl || k == Key.RightCtrl ||
k == Key.LeftShift || k == Key.RightShift ||
k == Key.LeftAlt || k == Key.RightAlt ||
k == Key.LWin || k == Key.RWin)
return true;
else
return false;
}
private ModifierKeys GetModifierKey(Key k)
{
if (k == Key.LeftCtrl || k == Key.RightCtrl)
return ModifierKeys.Control;
if (k == Key.LeftShift || k == Key.RightShift)
return ModifierKeys.Shift;
if (k == Key.LeftAlt || k == Key.RightAlt)
return ModifierKeys.Alt;
if (k == Key.LWin || k == Key.RWin)
return ModifierKeys.Windows;
return ModifierKeys.None;
}
有人想出禁用快捷命令但保留击键的想法吗?
谢谢!
我认为可以使用相应的应用程序命令使用自定义 CommandBindings
覆盖这些。在处理程序中将 ExecutedRoutedEventArgs.Handled
设置为 true
。
另外:就可用性而言,这是个坏主意。
示例:
<TextBox>
<TextBox.CommandBindings>
<CommandBinding Command="Paste" Executed="CommandBinding_Executed"/>
</TextBox.CommandBindings>
</TextBox>
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
这可能不是最优雅的解决方案,但对我来说很管用。我需要一个接受所有输入键而不触发快捷命令的文本框,以便用户可以将热键更改为他们想要的任何内容
class NoShortcutTextBox : TextBox
{
/// <summary>
/// Occurs when a key is pressed while focus is on this element. Apply to all shortcuts like
/// Ctrl-C or Ctrl-V
/// </summary>
public new event KeyEventHandler KeyDown;
public NoShortcutTextBox()
{
CommandManager.AddPreviewCanExecuteHandler(this, CanExecute);
// Workaround as we cannot raise event in base class, so we hide it and use
// our version of KeyDown instead
base.KeyDown += (sender, e) => KeyDown(sender, e);
// --Demo--
KeyDown += (sender, e) =>
{
// Fetch the actual shortcut key
var key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin) return;
var sb = new StringBuilder();
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
sb.Append("Ctrl+");
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
{
sb.Append("Shift+");
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
{
sb.Append("Alt+");
}
Console.WriteLine(sb.Append(key.ToString()).ToString());
};
}
private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
if (!(e.Command is RoutedUICommand command)) return;
switch (command.Text)
{
case "Copy":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.C));
break;
case "Cut":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.X));
break;
case "Paste":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.V));
break;
case "Select All":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.A));
break;
case "Undo":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Z));
break;
case "Redo":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Y));
break;
case "Backspace":
case "DeletePreviousWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Back));
break;
case "Delete":
case "DeleteNextWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Delete));
break;
case "MoveToLineStart":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Home));
break;
case "MoveToLineEnd":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.End));
break;
case "ToggleInsert":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Insert));
break;
case "MoveUpByPage":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.PageUp));
break;
case "MoveDownByPage":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.PageDown));
break;
case "MoveLeftByCharacter":
case "MoveLeftByWord":
case "SelectLeftByWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Left));
break;
case "MoveRightByCharacter":
case "MoveRightByWord":
case "SelectRightByWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Right));
break;
case "MoveDownByLine":
case "MoveDownByParagraph":
case "SelectDownByParagraph":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Down));
break;
case "MoveUpByLine":
case "MoveUpByParagraph":
case "SelectUpByParagraph":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Up));
break;
}
}
private KeyEventArgs GetKeyEventArgs(Key key)
{
return new KeyEventArgs(
Keyboard.PrimaryDevice,
new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero), // dummy source
0,
key)
{
RoutedEvent = TextBox.KeyDownEvent,
};
}
}
您可以使用 e.Handled=true 删除 PreviewKeyDown 事件中的任何关键操作或执行任何其他操作:
private void yourControl_PreviewKeyDown(object sender, KeyEventArgs e) {
// Remove shortcut for Ctrl+C
if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control && e.Key == Key.C)
e.Handled = true;
}
我正在尝试一种从 WPF 应用程序中的文本框捕获组合键的方法。 到目前为止编写的代码(我在其他讨论中找到的)帮助我做到这一点,除了那些链接到快捷命令的组合(Ctrl+C、Ctrl+V、Ctrl+X...)。 我想捕获用户在文本框上按下的所有键(Space、Delete、Backspace 和上面的所有组合)。 这是代码:
int MaxKeyCount = 3;
List<Key> PressedKeys = new List<Key>();
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Handled) return;
//Check all previous keys to see if they are still pressed
List<Key> KeysToRemove = new List<Key>();
foreach (Key k in PressedKeys)
{
if (!Keyboard.IsKeyDown(k))
KeysToRemove.Add(k);
}
//Remove all not pressed keys
foreach (Key k in KeysToRemove)
PressedKeys.Remove(k);
//Add the key if max count is not reached
if (PressedKeys.Count < MaxKeyCount)
//Add the key if it is part of the allowed keys
//if (AllowedKeys.Contains(e.Key))
if (!PressedKeys.Contains(e.Key))
PressedKeys.Add(e.Key);
PrintKeys();
e.Handled = true;
}
private void PrintKeys()
{
//Print all pressed keys
string s = "";
if (PressedKeys.Count == 0) return;
foreach (Key k in PressedKeys)
if (IsModifierKey(k))
s += GetModifierKey(k) + " + ";
else
s += k + " + ";
s = s.Substring(0, s.Length - 3);
TextBox.Text = s;
}
private bool IsModifierKey(Key k)
{
if (k == Key.LeftCtrl || k == Key.RightCtrl ||
k == Key.LeftShift || k == Key.RightShift ||
k == Key.LeftAlt || k == Key.RightAlt ||
k == Key.LWin || k == Key.RWin)
return true;
else
return false;
}
private ModifierKeys GetModifierKey(Key k)
{
if (k == Key.LeftCtrl || k == Key.RightCtrl)
return ModifierKeys.Control;
if (k == Key.LeftShift || k == Key.RightShift)
return ModifierKeys.Shift;
if (k == Key.LeftAlt || k == Key.RightAlt)
return ModifierKeys.Alt;
if (k == Key.LWin || k == Key.RWin)
return ModifierKeys.Windows;
return ModifierKeys.None;
}
有人想出禁用快捷命令但保留击键的想法吗? 谢谢!
我认为可以使用相应的应用程序命令使用自定义 CommandBindings
覆盖这些。在处理程序中将 ExecutedRoutedEventArgs.Handled
设置为 true
。
另外:就可用性而言,这是个坏主意。
示例:
<TextBox>
<TextBox.CommandBindings>
<CommandBinding Command="Paste" Executed="CommandBinding_Executed"/>
</TextBox.CommandBindings>
</TextBox>
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
}
这可能不是最优雅的解决方案,但对我来说很管用。我需要一个接受所有输入键而不触发快捷命令的文本框,以便用户可以将热键更改为他们想要的任何内容
class NoShortcutTextBox : TextBox
{
/// <summary>
/// Occurs when a key is pressed while focus is on this element. Apply to all shortcuts like
/// Ctrl-C or Ctrl-V
/// </summary>
public new event KeyEventHandler KeyDown;
public NoShortcutTextBox()
{
CommandManager.AddPreviewCanExecuteHandler(this, CanExecute);
// Workaround as we cannot raise event in base class, so we hide it and use
// our version of KeyDown instead
base.KeyDown += (sender, e) => KeyDown(sender, e);
// --Demo--
KeyDown += (sender, e) =>
{
// Fetch the actual shortcut key
var key = (e.Key == Key.System ? e.SystemKey : e.Key);
if (key == Key.LeftShift || key == Key.RightShift
|| key == Key.LeftCtrl || key == Key.RightCtrl
|| key == Key.LeftAlt || key == Key.RightAlt
|| key == Key.LWin || key == Key.RWin) return;
var sb = new StringBuilder();
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
sb.Append("Ctrl+");
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
{
sb.Append("Shift+");
}
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
{
sb.Append("Alt+");
}
Console.WriteLine(sb.Append(key.ToString()).ToString());
};
}
private void CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.Handled = true;
if (!(e.Command is RoutedUICommand command)) return;
switch (command.Text)
{
case "Copy":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.C));
break;
case "Cut":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.X));
break;
case "Paste":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.V));
break;
case "Select All":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.A));
break;
case "Undo":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Z));
break;
case "Redo":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Y));
break;
case "Backspace":
case "DeletePreviousWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Back));
break;
case "Delete":
case "DeleteNextWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Delete));
break;
case "MoveToLineStart":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Home));
break;
case "MoveToLineEnd":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.End));
break;
case "ToggleInsert":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Insert));
break;
case "MoveUpByPage":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.PageUp));
break;
case "MoveDownByPage":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.PageDown));
break;
case "MoveLeftByCharacter":
case "MoveLeftByWord":
case "SelectLeftByWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Left));
break;
case "MoveRightByCharacter":
case "MoveRightByWord":
case "SelectRightByWord":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Right));
break;
case "MoveDownByLine":
case "MoveDownByParagraph":
case "SelectDownByParagraph":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Down));
break;
case "MoveUpByLine":
case "MoveUpByParagraph":
case "SelectUpByParagraph":
KeyDown?.Invoke(this, GetKeyEventArgs(Key.Up));
break;
}
}
private KeyEventArgs GetKeyEventArgs(Key key)
{
return new KeyEventArgs(
Keyboard.PrimaryDevice,
new HwndSource(0, 0, 0, 0, 0, "", IntPtr.Zero), // dummy source
0,
key)
{
RoutedEvent = TextBox.KeyDownEvent,
};
}
}
您可以使用 e.Handled=true 删除 PreviewKeyDown 事件中的任何关键操作或执行任何其他操作:
private void yourControl_PreviewKeyDown(object sender, KeyEventArgs e) {
// Remove shortcut for Ctrl+C
if ((Keyboard.Modifiers & ModifierKeys.Control) != ModifierKeys.Control && e.Key == Key.C)
e.Handled = true;
}