VB .NETで使える日付入力用テキストボックス

水曜日 , 2, 9月 2015 Leave a comment

マウスによる操作からタッチ操作までGUI全盛の昨今ですが、業務用システムの場合、キーボードで入力することが効率的となされる場合があります。
今回は、業務用のシステムでよくいただく要望を取り込んだ、日付入力専用のテキストボックスを作成してみました。
  実装した機能は以下の通りです。

  • 入力は西暦形式
  • 入力時にスラッシュやハイフンは不要
  • 表示は和暦形式(任意の書式設定可能)
' This software is distributed under the license of NYSL.
' ( http://www.kmonos.net/nysl/ )
Imports System.ComponentModel

'''
''' YYYYMMDD形式で入力し和暦形式で表示する
'''
'''
Public Class JpDateTextBox
    Inherits TextBox

    Private _calendar As System.Globalization.JapaneseCalendar
    Private _culture As System.Globalization.CultureInfo

    '''入力用の書式パターン
    Private Const _inputFormat As String = "yyyyMMdd"

    '''表示用の書式パターン
    Private _displayFormat As String = "gg yy年MM月dd日 (ddd)"

    '''
    Private _value As Nullable(Of Date)

    '''
    '''
    '''
    '''
    Public Sub New()

        MyBase.New()

        ' 和暦表示用のカレンダー/カルチャーを初期化
        _calendar = New System.Globalization.JapaneseCalendar()
        _culture = New System.Globalization.CultureInfo("ja-JP")
        _culture.DateTimeFormat.Calendar = _calendar

        ' ハンドラの定義
        AddHandler Me.GotFocus, AddressOf HandlerFocusChanged
        AddHandler Me.LostFocus, AddressOf HandlerFocusChanged
        AddHandler Me.TextChanged, AddressOf HandlerValueChanged

    End Sub

    '''
    ''' GotFocus/LostFocusのイベント発生時にハンドラでフォーマットの切り替えを行う
    '''
    '''
    '''
    '''
    Private Sub HandlerFocusChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

        ' コントロールにフォーカスがあるときは入力用のフォーマットに、
        ' ないときは表示用のフォーマットに
        If Me.Focused Then
            If _value IsNot Nothing Then
                Me.Text = Format(_value, _inputFormat)
            End If
        Else
            If _value IsNot Nothing Then
                Me.Text = _value.Value.ToString(_displayFormat, _culture)
            End If
        End If

    End Sub

    '''
    '''
    '''
    '''
    '''
    '''
    Private Sub HandlerValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

        ' コントロールにフォーカスがあるときは表示の更新をパスする
        If Me.Focused Then
            Return
        End If

        ' コントロールにフォーカスがないときは表示の更新を行う
        If _value IsNot Nothing Then
            Me.Text = _value.Value.ToString(_displayFormat, _culture)
        End If

    End Sub

    '''
    '''
    '''
    '''
    '''
    Protected Overrides Sub OnKeyPress(e As System.Windows.Forms.KeyPressEventArgs)

        If (e.KeyChar >= "0"c And e.KeyChar <= "9"c) Then

            If Me.SelectionLength = 0 AndAlso Text.Length >= 8 Then
                e.Handled = True
                Return
            End If

            Return
        End If

        If e.KeyChar = ControlChars.Back _
        OrElse e.KeyChar = ControlChars.Tab Then
            Return
        End If

        ' Enterキーを押されたタイミングで日付として認識可能かパースを試みる
        If e.KeyChar = ControlChars.Cr Then
            _value = Parse(Me.Text)
            Return
        End If

        ' 0~9、Back、Tab、Enter以外の時はキー入力を無視
        e.Handled = True

    End Sub

    '''
    '''
    '''
    '''
    '''
    Protected Overrides Sub OnValidating(e As System.ComponentModel.CancelEventArgs)
        ' 日付として認識可能かパースを試みる
        _value = Parse(Me.Text)
        MyBase.OnValidating(e)
    End Sub


    '''
    ''' 文字列のDate化
    '''
    '''
    ''' 
    ''' 
    Private Shared Function Parse(s As String) As Nullable(Of Date)

        Try

            ' 8文字(YYYYMMDD)未満の場合、日付として認識しない
            If s.Length < 8 Then
                Return Nothing
            End If

            ' YYYYMMDDを前提としてパース
            Return DateTime.Parse(s.Substring(0, 4) & "/" & s.Substring(4, 2) & "/" & s.Substring(6, 2))

        Catch ex As Exception
            Return Nothing
        End Try

    End Function

#Region "プロパティ"

    ''' 
    '''
    ''' 
    ''' 
    ''' 
    ''' 
    Public Shadows Property Value As Nullable(Of Date)
        Get
            If _value Is Nothing Then
                Return Nothing
            End If
            Return _value
        End Get

        Set(value As Nullable(Of Date))
            _value = value
            Me.Text = If(value Is Nothing, "", _value.Value.ToString(_displayFormat, _culture))
        End Set
    End Property


    ''' 
    ''' 表示書式
    ''' 
    ''' 
    ''' 
    ''' 
    Public Shadows Property DisplayFormat As String
        Get
            Return _displayFormat
        End Get

        Set(value As String)
            _displayFormat = value
            Me.Text = If(_value Is Nothing, "", _value.Value.ToString(_displayFormat, _culture))
        End Set
    End Property

#End Region

End Class

ソースのダウンロード: JpDateTextBox.zip
(動作確認はVisual Studio 2013 Update 5で行いました。未確認ですが、2010や2015でも動作すると思います。)

Tags:

Please give us your valuable comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください