57237


いつもお世話になっております．

WPFでプログラミング用のテキストエディタを実装していて，Ctrl+Dで文を複製する機能を作ろうとしていたのですが，文が複製される際に改行が入らなかったのです．  
調べていくうちに，Ctrl+Enterでは改行できないことがわかりました．(Ctrl+Dコマンドを実行際に複製する文をTextBoxに送っているのでコマンドが実行されている間はCtrlキーが押されている)  
AcceptsReturnプロパティはTrueに設定しているので，Ctrlキーが押されていなければちゃんと改行ができます．

Ctrl+Enterで改行ができないなら，InputManagerでEnterキーを送っても改行が入力されないことはわかるのですが，TextCompositionManagerでTextを送る際に”\r\n”を送っても改行が入力されないのが，よくわかりません．

どのようにすればCtrlキーが押された状態で改行を入力できるようになるのでしょうか．

開発環境はWindows 10(1803)，  
VisualStudio 2017 ，  
.NET Framework 4.5です．

以下ソースコードです

[code]

    class Editor : TextBox {
            //コンストラクタやほかの処理は省略
    
            private void SendText(string text)
            {
                    TextCompositionManager.StartComposition(new 
                    TextComposition(InputManager.Current, this, text));
            }
    
            private void SendKey(Key key)
            {
                    PresentationSource presentationSource = 
    PresentationSource.FromVisual(this);
                    InputManager.Current.ProcessInput(new 
                    KeyEventArgs(Keyboard.PrimaryDevice, presentationSource, 100, key)
                    {
                            RoutedEvent = PreviewKeyDownEvent
                    });
            }
    
            public void Duplicate() //Ctrl+D
            {
                    int current_line = GetCurrentLineNumber();
                    int current_start = SelectionStart;
                    string duptext = GetLineText(current_line);
                    SendText(Environment.NewLine + duptext);
                    SelectionStart = current_start;
            }
    }
    
[/code]

InputManagerやTextCompositionManagerを採用した理由については，将来RichTextBoxにコードを移植した際に，Textプロパティを直接書き換える方法使った場合，Rtf値がリセットされて色情報が消えてしまうからです．  
Ctrl+Dを押したときのイベント捕捉はXAMLのKeyBindingsで行っています．

よろしくお願いします．


CC BY-SA 4.0
2019-08-07T16:56:19.167
57232
2019-08-08T06:25:55.467
2019-08-08T06:25:55.467
32650
32650
question
c# .net wpf
WPFのTextBoxでAcceptsReturnをtrueにしたときCtrl+Enterで改行ができない


> どのようにすればCtrlキーが押された状態で改行を入力できるようになるのでしょうか．

プログラムコードで[強引に改行](https://stackoverflow.com/a/10549299)できます。

**MainWindow.xaml.cs**

[code]

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                //MyTextBox.PreviewKeyDown += MyTextBox_PreviewKeyDown;  // PreviewKeyDownではCtrl+Enterで改行できない
                MyTextBox.KeyDown += MyTextBox_KeyDown;
                InputManagerButton.Click += InputManagerButton_Click;
            }
    
            private void MyTextBox_KeyDown(object sender, KeyEventArgs e)
            {
                var textBox = (sender as TextBox);
                //Ctrlキーが押されている時、強引に改行する
                if (e.Key == Key.Enter && Keyboard.Modifiers == ModifierKeys.Control)
                {
                    var caretIndex = textBox.CaretIndex;
                    textBox.Text = textBox.Text.Insert(caretIndex, Environment.NewLine);
                    textBox.CaretIndex = caretIndex + Environment.NewLine.Length;
                }
    
                if (e.Key == Key.D && Keyboard.Modifiers == ModifierKeys.Control)
                {
                    //テキストを末尾にコピペする(+改行テスト)
                    textBox.Text = textBox.Text
                        + string.Format("\r\n改行する{0}", Environment.NewLine)
                        + @"\r\n" + "改行しない" + "\\r\\n"
                        + textBox.Text;
                }
            }
    
            private void InputManagerButton_Click(object sender, RoutedEventArgs e)
            {
                MyTextBox.Focus();
                var enterEvent = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Enter);
                enterEvent.RoutedEvent = Keyboard.KeyDownEvent;
                InputManager.Current.ProcessInput(enterEvent);
            }
        }
    }
    
[/code]

**MainWindow.xaml**

[code]

    <Window x:Class="WpfApp1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp1"
            mc:Ignorable="d"
            Title="MainWindow" Height="200" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBox Name="MyTextBox" AcceptsReturn="True" />
            <Button Grid.Row="1" Name="InputManagerButton" Content="Emulate InputManager"/>
        </Grid>
    </Window>
    
[/code]

しかし下記の理由が分かりません。

  1. Ctrl+Dで文を複製する機能を作ろうとしていたのですが，文が複製される際に改行が入らなかった
  2. TextCompositionManagerでTextを送る際に"\r\n"を送っても改行が入力されない

もしかして文を複製する時に`PreviewKeyDown`イベントから`InputManager`を使って、過去のキーストロークを再現しようとしていますか？  
その場合は`InputManager`を採用した理由とサンプルコードを質問に追記していただくと回答しやすいです。  
特に理由がなければ回答コードのように、Textプロパティを直接書き換えるべきだと思います。(プロパティを直接書き換えればCtrl+Enter問題も自動的に解決します)

`\r\n`を送れば改行されるはずですが、`@"\r\n"`やファイルから読み込んだ"\r\n"という文字列(string型としては`\\r\\n`でエスケープされる)の場合は改行されません。  
追加の条件がある場合はこちらも追記をお願いします。

蛇足ですが、サンプルコードでCtrlキーを押下しながら`InputManagerButton`をクリックした場合は、`PreviewKeyDown`イベントではフォーカス移動した瞬間に`Key.LeftCtrl`がMyTextBox_KeyDownイベントの引数に送られてEnterキーのイベントが処理されませんでした。

ちなみに[TextWrapping](https://docs.microsoft.com/ja-
jp/dotnet/api/system.windows.forms.textboxbase.wordwrap?view=netframework-4.8#System_Windows_Forms_TextBoxBase_WordWrap)プロパティはテキストの横幅がTextBoxより長くなった時の文字列折り返し方法を指定するものなので、今回の質問とは関係ないはずです。


CC BY-SA 4.0
2019-08-08T01:58:22.050
57237
2019-08-08T01:58:22.050
9820
57232
answer