Skip Navigation Linksホーム > ライブラリ > テキストボックス > テキストボックスにテキスト変更中イベントを作成する

テキストボックスにテキスト変更中イベントを作成する

言語フィルタ:

概要

テキストボックスにテキスト変更中イベントを作成する方法を紹介します。

このイベントを利用すると、入力した文字が描画される前にキャンセルできるようになります。数字のみ受け付けるようにするなど、入力制限をする場合に使用します。

対象コントロール

  • System.Windows.Forms.TextBox

解説

テキスト変更中のイベントで使用する TextChangingEventArgs クラスを作成します。このクラスは CancelEventArgs クラスを継承することで Cancel プロパティが使えるようになります。また、変更後のテキストを示す NewText プロパティを追加します。

展開されたイメージ TextChangingEventArgs クラス - Visual Basic
コピーイメージ コードのコピー
Public Class TextChangingEventArgs
    Inherits System.ComponentModel.CancelEventArgs

    Public Sub New()
        Me._NewText = String.Empty
    End Sub

    Public Sub New(ByVal text As String)
        Me._NewText = text
    End Sub

    Private _NewText As String
    Public ReadOnly Property NewText() As String
        Get
            Return Me._NewText
        End Get
    End Property

End Class
展開されたイメージ TextChangingEventArgs クラス - C#
コピーイメージ コードのコピー
class TextChangingEventArgs : System.ComponentModel.CancelEventArgs
{
    public TextChangingEventArgs()
    {
        this._NewText = string.Empty;
    }

    public TextChangingEventArgs(string text)
    {
        this._NewText = text;
    }

    private string _NewText;

    public string NewText
    {
        get { return this._NewText; }
    }
}

テキスト変更中を示すイベントを TextChanging イベントとして定義します。このイベントをテキストが変更される直前に発生させます。変更内容をキャンセルする場合は TextChangingEventArgs クラスの Cancel プロパティに True を設定します。

展開されたイメージ TextChanging イベントの定義 - Visual Basic
コピーイメージ コードのコピー
Public Event TextChanging(ByVal sender As Object, ByVal e As TextChangingEventArgs)

Protected Overridable Sub OnTextChanging(ByVal e As TextChangingEventArgs)
    RaiseEvent TextChanging(Me, e)
End Sub
展開されたイメージ TextChanging イベントの定義 - C#
コピーイメージ コードのコピー
public delegate void TextChangingEventHandler(object sender, TextChangingEventArgs e);
public event TextChangingEventHandler TextChanging;

protected virtual void OnTextChanging(TextChangingEventArgs e)
{
    if (TextChanging != null)
    {
        TextChanging(this, e);
    }
}

テキストが変更される直前のタイミングは、次のメッセージが送られてきた時です。WM_CHAR, WM_PASTE, WM_KEYDOWN。各メッセージを処理するために WndProc メソッドをオーバーライドします。

WM_CHAR メッセージは文字を入力した時に送られてきます。WM_CHAR メッセージの WParam に入力した文字の文字コードが入っています。この文字コードから擬似的に入力後のテキストを作成し、それを TextChangingEventArgs クラスの NewText プロパティに設定し TextChanging イベントを発生させます。

TextChanging イベントの受信側で TextChangingEventArgs クラスの Cancel プロパティに True を設定した場合は、基本クラスの WndProc メソッドを呼ばないことで、入力された文字をキャンセルすることが出来ます。

展開されたイメージ 文字入力時の処理 - Visual Basic
コピーイメージ コードのコピー
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Const WM_CHAR As Integer = &H102

    Select Case m.Msg
        Case WM_CHAR
            Dim e As New TextChangingEventArgs(Me.CreateNewText(ChrW(m.WParam.ToInt32)))
            Me.OnTextChanging(e)
            If e.Cancel = True Then
                Return
            End If
    End Select

    MyBase.WndProc(m)
End Sub
展開されたイメージ 擬似的に入力後のテキストを作成する処理 - Visual Basic
コピーイメージ コードのコピー
Private Function CreateNewText(ByVal inputText As String) As String
    Return Me.CreateNewText(inputText, False)
End Function

Private Function CreateNewText(ByVal inputText As String, ByVal deleteKey As Boolean) As String
    Dim newText As String = Me.Text
    newText = newText.Remove(Me.SelectionStart, Me.SelectionLength)

    ' Delete キーを入力
    If deleteKey Then
        If Me.SelectionLength = 0 AndAlso Me.SelectionStart < Me.TextLength Then
            newText = newText.Remove(Me.SelectionStart, 1)
        End If

        Return newText
    End If

    If Me.Multiline = False Then
        Dim crIndex As Integer = inputText.IndexOf(ControlChars.Cr)
        If crIndex > 0 Then
            inputText = inputText.Remove(crIndex)
        End If

        Dim lrIndex As Integer = inputText.IndexOf(ControlChars.Lf)
        If lrIndex > 0 Then
            inputText = inputText.Remove(lrIndex)
        End If
    End If

    If inputText = String.Empty Then
        Return newText
    End If

    ' BackSpace キーを入力
    If Convert.ToInt32(inputText.Chars(0)) = Keys.Back Then
        If Me.SelectionLength = 0 AndAlso Me.SelectionStart > 0 Then
            newText = newText.Remove(Me.SelectionStart - 1, 1)
        End If
    Else
        newText = newText.Insert(Me.SelectionStart, inputText)
    End If

    Return newText
End Function
展開されたイメージ 文字入力時の処理 - C#
コピーイメージ コードのコピー
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    const int WM_CHAR = 0x102;

    switch (m.Msg)
    {
        case WM_CHAR:
            {
                TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(Convert.ToString((char)(m.WParam.ToInt32()))));
                this.OnTextChanging(e);
                if (e.Cancel == true)
                {
                    return;
                }
            }
            break;
    }

    base.WndProc(ref m);
}
展開されたイメージ 擬似的に入力後のテキストを作成する処理 - C#
コピーイメージ コードのコピー
private string CreateNewText(string inputText)
{
    return this.CreateNewText(inputText, false);
}

private string CreateNewText(string inputText, bool deleteKey)
{
    string newText = this.Text;
    newText = newText.Remove(this.SelectionStart, this.SelectionLength);

    // Delete キーを入力
    if (deleteKey)
    {
        if (this.SelectionLength == 0 && this.SelectionStart < this.TextLength)
        {
            newText = newText.Remove(this.SelectionStart, 1);
        }

        return newText;
    }

    if (this.Multiline == false)
    {
        int crIndex = inputText.IndexOf("\r");
        if (crIndex > 0)
        {
            inputText = inputText.Remove(crIndex);
        }

        int lrIndex = inputText.IndexOf("\n");
        if (lrIndex > 0)
        {
            inputText = inputText.Remove(lrIndex);
        }
    }

    if (inputText == string.Empty)
    {
        return newText;
    }

    // BackSpace キーを入力
    if (Convert.ToInt32(inputText[0]) == (int)Keys.Back)
    {
        if (this.SelectionLength == 0 && this.SelectionStart > 0)
        {
            newText = newText.Remove(this.SelectionStart - 1, 1);
        }
    }
    else
    {
        newText = newText.Insert(this.SelectionStart, inputText);
    }

    return newText;
}

WM_PASTE メッセージは貼り付け操作をした時に送られてきます。WM_PASTE メッセージには貼り付けた文字列が含まれていないため、クリップボードからテキストを取得します。後は WM_CHAR メッセージの処理と同様に、擬似的に貼り付け後のテキストを作成し TextChanging イベントを発生させます。

展開されたイメージ 貼り付け操作時の処理 - Visual Basic
コピーイメージ コードのコピー
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Const WM_PASTE As Integer = &H302

    Select Case m.Msg
        Case WM_PASTE
            Dim clipText As String = CType(Clipboard.GetDataObject().GetData(DataFormats.Text), String)
            If clipText IsNot Nothing Then
                Dim e As New TextChangingEventArgs(Me.CreateNewText(clipText))
                Me.OnTextChanging(e)
                If e.Cancel = True Then
                    Return
                End If
            End If
    End Select

    MyBase.WndProc(m)
End Sub
展開されたイメージ 貼り付け操作時の処理 - C#
コピーイメージ コードのコピー
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    const int WM_PASTE = 0x302;

    switch (m.Msg)
    {
        case WM_PASTE:
            string clipText = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
            if (clipText != null)
            {
                TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(clipText));
                this.OnTextChanging(e);
                if (e.Cancel == true)
                {
                    return;
                }
            }
            break;
    }

    base.WndProc(ref m);
}

WM_KEYDOWN メッセージはキーを押した時に送られてきます。テキストを Delete キーで削除した時だけは WM_CHAR メッセージが送られてきません。そのため Delete キーを入力されたタイミングだけを WM_KEYDOWN メッセージで処理をします。

WM_KEYDOWN メッセージの WParam に Delete キーを示す値 (46) が入っている時が Delete キーを入力した時です。後は WM_CHAR メッセージの処理と同様に、擬似的に Delete キーを入力後のテキストを作成し TextChanging イベントを発生させます。WM_KEYDOWN メッセージで Delete キーの入力をキャンセルする場合はWM_KEYDOWN メッセージ の Result プロパティに True (1) を設定します。

展開されたイメージ Delete キー入力時の処理 - Visual Basic
コピーイメージ コードのコピー
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    Const WM_KEYDOWN As Integer = &H100

    Select Case m.Msg
        Case WM_KEYDOWN
            If m.WParam.ToInt32 = Keys.Delete Then
                Dim e As New TextChangingEventArgs(Me.CreateNewText(String.Empty, True))
                Me.OnTextChanging(e)
                If e.Cancel = True Then
                    m.Result = New IntPtr(1) ' True
                    Return
                End If
            End If
    End Select

    MyBase.WndProc(m)
End Sub
展開されたイメージ Delete キー入力時の処理 - C#
コピーイメージ コードのコピー
protected override void WndProc(ref System.Windows.Forms.Message m)
{
    const int WM_KEYDOWN = 0x100;

    switch (m.Msg)
    {
        case WM_KEYDOWN:
            if (m.WParam.ToInt32() == (int)Keys.Delete)
            {
                TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(string.Empty, true));
                this.OnTextChanging(e);
                if (e.Cancel == true)
                {
                    m.Result = new IntPtr(1); // true
                    return;
                }
            }
            break;
    }

    base.WndProc(ref m);
}

ソースコード

TextBox コントロールにテキストの変更中イベントを作成するサンプルを紹介します。

ソースコードは解説で紹介した内容をまとめたものになっています。

TextChanging イベントの利用例では数字以外の文字を受け付けないようにしています。

展開されたイメージ Visual Basic
コピーイメージ コードのコピー
Imports System
Imports System.ComponentModel
Imports System.Windows.Forms
Imports Microsoft.VisualBasic

Namespace Extentions

    Public Class ChangingTextBox
        Inherits System.Windows.Forms.TextBox

        <Category("プロパティ変更")> _
        <Description("Text プロパティの値がコントロールで変更される直前に発生します。")> _
        Public Event TextChanging(ByVal sender As Object, ByVal e As TextChangingEventArgs)

        Protected Overridable Sub OnTextChanging(ByVal e As TextChangingEventArgs)
            RaiseEvent TextChanging(Me, e)
        End Sub

        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            Const WM_KEYDOWN As Integer = &H100
            Const WM_CHAR As Integer = &H102
            Const WM_PASTE As Integer = &H302

            Select Case m.Msg
                Case WM_KEYDOWN
                    If m.WParam.ToInt32 = Keys.Delete Then
                        Dim e As New TextChangingEventArgs(Me.CreateNewText(String.Empty, True))
                        Me.OnTextChanging(e)
                        If e.Cancel = True Then
                            m.Result = New IntPtr(1) ' True
                            Return
                        End If
                    End If

                Case WM_CHAR
                    Dim e As New TextChangingEventArgs(Me.CreateNewText(ChrW(m.WParam.ToInt32)))
                    Me.OnTextChanging(e)
                    If e.Cancel = True Then
                        Return
                    End If

                Case WM_PASTE
                    Dim clipText As String = CType(Clipboard.GetDataObject().GetData(DataFormats.Text), String)
                    If clipText IsNot Nothing Then
                        Dim e As New TextChangingEventArgs(Me.CreateNewText(clipText))
                        Me.OnTextChanging(e)
                        If e.Cancel = True Then
                            Return
                        End If
                    End If

            End Select

            MyBase.WndProc(m)
        End Sub

        Private Function CreateNewText(ByVal inputText As String) As String
            Return Me.CreateNewText(inputText, False)
        End Function

        Private Function CreateNewText(ByVal inputText As String, ByVal deleteKey As Boolean) As String
            Dim newText As String = Me.Text
            newText = newText.Remove(Me.SelectionStart, Me.SelectionLength)

            ' Delete キーを入力
            If deleteKey Then
                If Me.SelectionLength = 0 AndAlso Me.SelectionStart < Me.TextLength Then
                    newText = newText.Remove(Me.SelectionStart, 1)
                End If

                Return newText
            End If

            If Me.Multiline = False Then
                Dim crIndex As Integer = inputText.IndexOf(ControlChars.Cr)
                If crIndex > 0 Then
                    inputText = inputText.Remove(crIndex)
                End If

                Dim lrIndex As Integer = inputText.IndexOf(ControlChars.Lf)
                If lrIndex > 0 Then
                    inputText = inputText.Remove(lrIndex)
                End If
            End If

            If inputText = String.Empty Then
                Return newText
            End If

            ' BackSpace キーを入力
            If Convert.ToInt32(inputText.Chars(0)) = Keys.Back Then
                If Me.SelectionLength = 0 AndAlso Me.SelectionStart > 0 Then
                    newText = newText.Remove(Me.SelectionStart - 1, 1)
                End If
            Else
                newText = newText.Insert(Me.SelectionStart, inputText)
            End If

            Return newText
        End Function

    End Class

End Namespace
展開されたイメージ TextChangingEventArgs クラス - Visual Basic
コピーイメージ コードのコピー
Namespace Extentions

    Public Class TextChangingEventArgs
        Inherits System.ComponentModel.CancelEventArgs

        Public Sub New()
            Me._NewText = String.Empty
        End Sub

        Public Sub New(ByVal text As String)
            Me._NewText = text
        End Sub

        Private _NewText As String
        Public ReadOnly Property NewText() As String
            Get
                Return Me._NewText
            End Get
        End Property

    End Class

End Namespace
展開されたイメージ TextChanging イベントの利用例 - Visual Basic
コピーイメージ コードのコピー
Private Sub ChangingTextBox1_TextChanging(ByVal sender As System.Object, ByVal e As Extentions.TextChangingEventArgs) Handles ChangingTextBox1.TextChanging
    Dim r As New System.Text.RegularExpressions.Regex("[^0-9]")
    If r.Match(e.NewText).Success = True Then
        e.Cancel = True
    End If
End Sub
展開されたイメージ C#
コピーイメージ コードのコピー
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace Extentions
{
    class ChangingTextBox : System.Windows.Forms.TextBox
    {
        public delegate void TextChangingEventHandler(object sender, TextChangingEventArgs e);

        [Category("プロパティ変更")]
        [Description("Text プロパティの値がコントロールで変更される直前に発生します。")]
        public event TextChangingEventHandler TextChanging;

        protected virtual void OnTextChanging(TextChangingEventArgs e)
        {
            if (TextChanging != null)
            {
                TextChanging(this, e);
            }
        }

        protected override void WndProc(ref System.Windows.Forms.Message m)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_CHAR = 0x102;
            const int WM_PASTE = 0x302;

            switch (m.Msg)
            {
                case WM_KEYDOWN:
                    if (m.WParam.ToInt32() == (int)Keys.Delete)
                    {
                        TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(string.Empty, true));
                        this.OnTextChanging(e);
                        if (e.Cancel == true)
                        {
                            m.Result = new IntPtr(1); // true
                            return;
                        }
                    }
                    break;

                case WM_CHAR:
                    {
                        TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(Convert.ToString((char)(m.WParam.ToInt32()))));
                        this.OnTextChanging(e);
                        if (e.Cancel == true)
                        {
                            return;
                        }
                    }
                    break;

                case WM_PASTE:
                    string clipText = (string)Clipboard.GetDataObject().GetData(DataFormats.Text);
                    if (clipText != null)
                    {
                        TextChangingEventArgs e = new TextChangingEventArgs(this.CreateNewText(clipText));
                        this.OnTextChanging(e);
                        if (e.Cancel == true)
                        {
                            return;
                        }
                    }
                    break;
            }

            base.WndProc(ref m);
        }

        private string CreateNewText(string inputText)
        {
            return this.CreateNewText(inputText, false);
        }

        private string CreateNewText(string inputText, bool deleteKey)
        {
            string newText = this.Text;
            newText = newText.Remove(this.SelectionStart, this.SelectionLength);

            // Delete キーを入力
            if (deleteKey)
            {
                if (this.SelectionLength == 0 && this.SelectionStart < this.TextLength)
                {
                    newText = newText.Remove(this.SelectionStart, 1);
                }

                return newText;
            }

            if (this.Multiline == false)
            {
                int crIndex = inputText.IndexOf("\r");
                if (crIndex > 0)
                {
                    inputText = inputText.Remove(crIndex);
                }

                int lrIndex = inputText.IndexOf("\n");
                if (lrIndex > 0)
                {
                    inputText = inputText.Remove(lrIndex);
                }
            }

            if (inputText == string.Empty)
            {
                return newText;
            }

            // BackSpace キーを入力
            if (Convert.ToInt32(inputText[0]) == (int)Keys.Back)
            {
                if (this.SelectionLength == 0 && this.SelectionStart > 0)
                {
                    newText = newText.Remove(this.SelectionStart - 1, 1);
                }
            }
            else
            {
                newText = newText.Insert(this.SelectionStart, inputText);
            }

            return newText;
        }
    }
}
展開されたイメージ TextChangingEventArgs クラス - C#
コピーイメージ コードのコピー
namespace Extentions
{
    class TextChangingEventArgs : System.ComponentModel.CancelEventArgs
    {
        public TextChangingEventArgs()
        {
            this._NewText = string.Empty;
        }

        public TextChangingEventArgs(string text)
        {
            this._NewText = text;
        }

        private string _NewText;

        public string NewText
        {
            get { return this._NewText; }
        }
    }
}
展開されたイメージ TextChanging イベントの利用例 - C#
コピーイメージ コードのコピー
private void changingTextBox1_TextChanging(object sender, Extentions.TextChangingEventArgs e)
{
    System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex("[^0-9]");
    if (r.Match(e.NewText).Success == true)
    {
        e.Cancel = true;
    }
}