Wpf RichTextBox通过发送程序化的键击执行命令

时间:2015-05-11 09:20:07

标签: c# wpf richtextbox keystroke

我需要向RichTextBox发送击键,最后应该执行一些命令,如ToggleBold或SelectAll等。

我在循环中调用以下代码来迭代SomeEventSomeKey对。

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 - KeyUpEventPreviewKeyDownEvent - PreviewKeyUpEventPreviewKeyDownEvent - KeyDownEvent - PreviewKeyUpEvent - KeyUpEvent,但都没有效果。

RichTextBox实际上捕获了事件但它没有对它们做出反应。如果我发送字母数字字符(它们不打印在RichTextBox上)也是如此。但是,如果我发送Keys.Back,它实际上会识别并删除文本中的字符。

SendKeyskeybd_event等解决方案不适用,因为在发送击键时程序将在后台。

有没有办法将按键发送到控件,就像它们真的是由用户发送一样?

1 个答案:

答案 0 :(得分:2)

<强>更新

你问了

  

有没有办法将按键发送到控件,就像它们真的是由用户发送一样?

     

SendKeyskeybd_event等解决方案不适用,因为在发送击键时程序将在后台。

从浏览WPF reference source看来,可能无法满足您在后台执行此操作的要求:

  1. RichTextBoxconstructed时,会调用TextEditor.RegisterCommandHandlers()来注册RichTextBox类的全局命令,包括快捷方式。

  2. TextEditor.RegisterCommandHandlers()依次调用TextEditorParagraphs._RegisterClassHandlers()之类的方法来注册该类的特定命令。

  3. 这些反过来调用CommandHelpers.RegisterCommandHandler()来注册每个命令以及该类的相关(硬编码)快捷方式。快捷方式编码为KeyGesture

  4. RegisterCommandHandler()依次调用CommandManager.RegisterClassInputBinding()来注册该课程的每个快捷手势。

  5. CommandManager将快捷手势存储在private static dictionary

     private static HybridDictionary _classInputBindings = new HybridDictionary();
    
  6. 此词典没有“获取”访问权限。它使用的唯一其他地方是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;
                }
            }
        }
    
  7. classInputBindings.FindMatch()来电KeyGesture.Matches()

  8. 但是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键。

  9. 如果您删除了在后台执行此操作的要求,则P / Invoking SendInput将成为解决方案。

    所以我认为硬编码命令的解决方法可能是您最好的解决方案。

    原始答案

    完全回答您的具体问题,但可以解决您的问题。

    您可以使用

    执行任何standard public static editing commands,例如ToggleBoldstandard 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);
        }
    }