MaskedTextBox コントロールでキーボード入力を処理する場合の注意点について

こんにちは、Visual Studio サポート チームです。

今回は、MaskedTextBox コントロール (以下、MaskedTextBox) でキーボード入力を処理する場合の注意点についてご紹介します。

MaskedTextBox は、マスク パターンを指定して、入力制限を行うことができる TextBox です。

郵便番号、日時、電話番号などの標準的なマスクは、あらかじめ用意されており、マスクを設定しておくと、その形式に合わない入力を拒否できます。
入力が不可欠な文字スペース、英数字だけ受け付ける、など様々な条件を組み合わせて、マスクをきめ細かく作成することもできます。
また、パスワードなどの入力を受け付ける場合、画面に入力された文字を表示せず、代替文字を表示するような設定もできる非常に便利なコントロールです。

この MaskedTextBox の内部では、Enter キーの入力に対して他のキーとは異なる特別な処理が実装されていますので、ご注意いただく必要があります。

MaskedTextBox コントロールでの特別な処理について

まず、キーが押された時に発生するキー イベントの順番は、次のようになります。

   KeyDown → KeyPress → KeyUp

MaskedTextBox では、 KeyDown イベントにおいて、Enter キーが検知されると、コントロール内部で特殊なフラグが設定されます。
このフラグは、KeyPress イベント内で再設定されます。
このように、MaskedTextBox が Enter キーを他のキーとは異なる特別なキーとして処理しています。

しかし、他のコントロールによるイベント処理の影響で、KeyPress イベントがキャンセルされると、上記フラグが設定されたままとなるため、次の文字入力以降で不整合が発生します。
Windows フォームでは、キーボード メッセージがコントロールに到達する前に、それらをフォーム レベルで処理できますが、この Enter キーに対する特別な処理のために、問題が発生することがあります。

注意が必要なケースについて、具体例と合わせてご説明します。

注意が必要な例

Form 上に、MaskedTextBox を配置し、Enter キーが押された際に、次のコントロールにフォーカスを移動する処理を実装します。
ここでは、Form の KeyPress イベント ハンドラ内で、明示的に TAB キーを発生させ、イベント処理をキャンセルします。
たとえば、以下のソース コードを実装します。

  Private Sub Form_KeyPress(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress

        Dim KeyAscii As Short = Asc(eventArgs.KeyChar)
        ‘ Enter キーが押下された場合
        If KeyAscii = System.Windows.Forms.Keys.Return Then
            System.Windows.Forms.SendKeys.Send("{TAB}")
            ‘ イベントキャンセル
            eventArgs.Handled = True
        End If

  End Sub

上記のように、Enter キーを押下した場合に、Form の KeyPress イベントでイベントがキャンセルされると、MaskedTextBox の KeyPress イベントが発生しない状態となります。
このため、前項の MaskedTextBox 内の特殊なフラグが設定されたままとなり、次の文字入力以降で、不整合が発生します。

対処方法

イベントのキャンセルの影響で MaskedTextBox の KeyPress イベントが発生しなくなる現象については、以下の 2 通りの対処方法が考えられます。

  1. フラグが立たないように、MaskedTextBox の KeyDown が発生しないようにする
    → Form の KeyDown で、 KeyPressEventArgs.Handled = True を行う。
  2. MaskedTextBox の KeyDown イベントと KeyPress イベントの両方が発生するようにする
    → Form の KeyPress で、KeyPressEventArgs.Handled = True を行わない。

最後に

以下の技術資料にもあるように、イベントをキャンセルする処理はサポートされており、一般的にもよく利用されるものです。

方法 : キーボード入力をフォーム レベルで処理する
<https://msdn.microsoft.com/ja-jp/library/ms171538.aspx>

ただし、今回の MaskedTextBox のように、独自にイベント処理をしているコントロールもあるため、イベントのキャンセル処理を利用される場合は、十分な検証を行ってください。