LoginSignup
1
2

More than 3 years have passed since last update.

RichTextBoxのTextを変更していないのにTextChangedイベントが発生してハマったので調べてみた (C#)

Last updated at Posted at 2021-02-26

1. 結論

書式設定をするだけでもTextChangedイベントが発生する。

2. 実験

2.1 実験用コード

RichTextBoxTest.cs

using System;
using System.Drawing;
using System.Windows.Forms;

class RichTextBoxTest:Form
{
    RichTextBox rtxt;

    RichTextBoxTest()
    {
        ClientSize = new Size(400,300);

        Controls.Add( rtxt = new RichTextBox() {
            Multiline = true,
            Location = new Point(0,0),
            Size = new Size(400,270),
        });

        Button btn;
        Controls.Add( btn = new Button() {
            Location = new Point(0,270),
            Size = new Size(400,30),
            Text = "SetColor",
        });

        rtxt.TextChanged += Rtxt_TextChanged;

        btn.Click += (s,e)=>{SetColor();};
    }

    void Rtxt_TextChanged(object sender, EventArgs e)
    {
        Console.WriteLine("TextChanged called.");
    }


    void SetColor()
    {
        Console.WriteLine("setting SelectionBackColor.");
        rtxt.SelectionBackColor = Color.Yellow;

        Console.WriteLine("setting SelectionColor.");
        rtxt.SelectionColor = Color.Blue;

        Font fontForTest = new Font("MS ゴシック", 12);
        Console.WriteLine("setting SelectionFont.");
        rtxt.SelectionFont = fontForTest;

        Console.WriteLine("end of UpdateColor.");
    }

    [STAThread]
    public static void Main(string[] args)
    {
        Application.Run(new RichTextBoxTest());
    }
}

2.2. 実行結果

RichTextBoxにテキストを1文字入力して、全選択し、ボタンを押した結果。

コンソール出力

TextChanged called.
setting SelectionBackColor.
TextChanged called.
setting SelectionColor.
TextChanged called.
setting SelectionFont.
TextChanged called.
end of UpdateColor.

RichTextBoxの以下のいずれのプロパティに対しても、設定時に TextChanged イベントが発生しています。

  • SelectionBackColor
  • SelectionColor
  • SelectionFont

3. 内部仕様調査

3.1. 仕様記載

仕様記載上は、そのようには読み取れない。

Control.TextChanged Event (System.Windows.Forms) | Microsoft Docs

Occurs when the Text property value changes.

3.2. 内部コード

dotnet451\Source\ndp\fx\src\WinForms\Managed\System\WinForms

RichTextBox.csより抜粋

public Color SelectionColor {
    get {
        省略
    }
    set {
        ForceHandleCreate();
        NativeMethods.CHARFORMATA cf = GetCharFormat(true);
        cf.dwMask = RichTextBoxConstants.CFM_COLOR;
        cf.dwEffects = 0;
        cf.crTextColor = ColorTranslator.ToWin32(value);

        // set the format information
        UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);
    }
}

明示的にTextChangedイベントを発火させている処理は見当たらない。
SendMessageが要因っぽい予感。

WindowsのMessageを処理してTextChangedイベントを発火しているのは、継承元のTextBoxBaseクラスのよう。

TextBoxBase.csより抜粋

private void WmReflectCommand(ref Message m) {
    if (!textBoxFlags[codeUpdateText] && !textBoxFlags[creatingHandle]) {
        if (NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.EN_CHANGE && CanRaiseTextChangedEvent) {
            OnTextChanged(EventArgs.Empty);
        }
        省略
    }
}

確証が持てないが、
UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);

NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.EN_CHANGEを満たすメッセージを発火しているのではないか。

3.3. Window Messageを監視してみる

3.3.1. テストコード

RichTextBoxを、下記に置き換えてRichTextBoxのWindowメッセージを監視してみた。

テストコード(C#)

public class MyRichTextBox:RichTextBox
{
    protected override void WndProc(ref Message m)
    {
        long wparam = m.WParam.ToInt64();
        long lparam = m.LParam.ToInt64();

        Console.Write( "Msg:0x"    +  m.Msg.ToString("X08"));
        Console.Write(" Wparam:0x" + wparam.ToString("X08"));
        Console.Write(" Lparam:0x" + lparam.ToString("X08"));
        Console.WriteLine();

        base.WndProc(ref m);
    }
}

3.3.2. 結果

コンソール出力

setting SelectionBackColor.
Msg:0x00000444 Wparam:0x00000001 Lparam:0x00D3E460
Msg:0x00002111 Wparam:0x030007CC Lparam:0x000707CC
TextChanged called.
setting SelectionColor.
Msg:0x0000043A Wparam:0x00000001 Lparam:0x00D3E440
Msg:0x00000444 Wparam:0x00000001 Lparam:0x00D3E4B0
Msg:0x00002111 Wparam:0x030007CC Lparam:0x000707CC
TextChanged called.
setting SelectionFont.
Msg:0x00000444 Wparam:0x00000001 Lparam:0x00D3E470
Msg:0x00002111 Wparam:0x030007CC Lparam:0x000707CC
TextChanged called.
end of UpdateColor.

UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf);

NativeMethods.Util.HIWORD(m.WParam) == NativeMethods.EN_CHANGEを満たすメッセージを発火しているのではないか。

内部コードをみると、

  • EM_SETCHARFORMAT0x444
  • EN_CHANGE0x0300

に対して、結果として、

Msg:0x00000444 Wparam:.......... Lparam:........
Msg:.......... Wparam:0x0300.... Lparam:........

が得られているため、推測の裏どりが取れた。

参考サイト

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2