我需要向RichTextBox发送击键,最后应该执行一些命令,如ToggleBold或SelectAll等。
我在循环中调用以下代码来迭代SomeEvent
和SomeKey
对。
PresentationSource presentationSource = PresentationSource.FromVisual(RichTextBoxControl);
if (presentationSource == null)
{
return;
}
if(SomeEvent == KeyDownEvent)
{
//InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = PreviewKeyDownEvent });
InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = KeyDownEvent });
}
else if (SomeEvent == KeyUpEvent)
{
//InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = PreviewKeyUpEvent });
InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, SomeKey) { RoutedEvent = KeyUpEvent });
}
例如,为了激活ToggleBold,我在循环中调用以下对:
KeyDownEvent, Keys.Control
KeyDownEvent, Keys.B
KeyUpEvent, Keys.B
KeyUpEvent, Keys.Control
我尝试了KeyDownEvent - KeyUpEvent
,PreviewKeyDownEvent - PreviewKeyUpEvent
和PreviewKeyDownEvent - KeyDownEvent - PreviewKeyUpEvent - KeyUpEvent
,但都没有效果。
RichTextBox实际上捕获了事件但它没有对它们做出反应。如果我发送字母数字字符(它们不打印在RichTextBox上)也是如此。但是,如果我发送Keys.Back
,它实际上会识别并删除文本中的字符。
SendKeys
和keybd_event
等解决方案不适用,因为在发送击键时程序将在后台。
有没有办法将按键发送到控件,就像它们真的是由用户发送一样?
答案 0 :(得分:2)
<强>更新强>
你问了
有没有办法将按键发送到控件,就像它们真的是由用户发送一样?
SendKeys
和keybd_event
等解决方案不适用,因为在发送击键时程序将在后台。
从浏览WPF reference source看来,可能无法满足您在后台执行此操作的要求:
当RichTextBox
为constructed时,会调用TextEditor.RegisterCommandHandlers()
来注册RichTextBox
类的全局命令,包括快捷方式。
TextEditor.RegisterCommandHandlers()
依次调用TextEditorParagraphs._RegisterClassHandlers()
之类的方法来注册该类的特定命令。
这些反过来调用CommandHelpers.RegisterCommandHandler()
来注册每个命令以及该类的相关(硬编码)快捷方式。快捷方式编码为KeyGesture
。
RegisterCommandHandler()
依次调用CommandManager.RegisterClassInputBinding()
来注册该课程的每个快捷手势。
CommandManager
将快捷手势存储在private static dictionary:
private static HybridDictionary _classInputBindings = new HybridDictionary();
此词典没有“获取”访问权限。它使用的唯一其他地方是CommandManager.TranslateInput(IInputElement targetElement, InputEventArgs inputEventArgs)
:
// 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;
}
}
}
classInputBindings.FindMatch()
来电KeyGesture.Matches()
。
但是KeyGesture.Matches()
使用global static Keyboard
device而不是InputEventArgs
来确定按下了哪个键修饰符:
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
KeyEventArgs keyEventArgs = inputEventArgs as KeyEventArgs;
if(keyEventArgs != null && IsDefinedKey(keyEventArgs.Key))
{
return ( ( (int)Key == (int)keyEventArgs.RealKey ) && ( this.Modifiers == Keyboard.Modifiers ) );
}
return false;
}
KeyEventArgs
甚至没有一个属性来表示是否按下了控件或alt键。
如果您删除了在后台执行此操作的要求,则P / Invoking SendInput将成为解决方案。
所以我认为硬编码命令的解决方法可能是您最好的解决方案。
原始答案
不完全回答您的具体问题,但可以解决您的问题。
您可以使用
执行任何standard public static editing commands,例如ToggleBold
或standard public static application commands,例如Undo
command.Execute(null, richTextBox);
其中command
是上面链接的文档中的任何静态命令。此外,您可以使用this answer
richTextBox.CaretPosition = richTextBox.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);
richTextBox.CaretPosition.InsertTextInRun("Hello, I am some text\n\n\n");
richTextBox.CaretPosition.InsertTextInRun("And some more text\n\n\n");
例如,以下内容将在指定的RichTextBox
的当前插入符位置插入一些文本,然后对所有文本进行各种编辑更改动画:
const int delayInterval = 500;
static void Do( RoutedUICommand command, RichTextBox richTextBox, ref int delay)
{
// https://stackoverflow.com/questions/15599884/how-to-put-delay-before-doing-an-operation-in-wpf
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(delay = delay + delayInterval)};
timer.Start();
timer.Tick += (sender, args) =>
{
timer.Stop();
command.Execute(null, richTextBox);
};
}
public static void TestTestProgrammaticCommandExecution(RichTextBox richTextBox)
{
// Insert some text at the caret position.
// https://stackoverflow.com/questions/2497291/how-do-i-move-the-caret-a-certain-number-of-positions-in-a-wpf-richtextbox
richTextBox.CaretPosition = richTextBox.CaretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);
richTextBox.CaretPosition.InsertTextInRun("Hello, I am some text\n\n\n");
richTextBox.CaretPosition.InsertTextInRun("And some more text\n\n\n");
int delay = 0;
// Do a bunch of editing commands.
Do(EditingCommands.MoveToDocumentStart, richTextBox, ref delay);
Do(EditingCommands.SelectToDocumentEnd, richTextBox, ref delay);
Do(EditingCommands.AlignCenter, richTextBox, ref delay);
Do(EditingCommands.AlignLeft, richTextBox, ref delay);
Do(EditingCommands.AlignRight, richTextBox, ref delay);
Do(EditingCommands.DecreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.IncreaseFontSize, richTextBox, ref delay);
Do(EditingCommands.Backspace, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(EditingCommands.ToggleBold, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Undo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
Do(ApplicationCommands.Redo, richTextBox, ref delay);
}
}