2011-11-29 11 views
1

tldr - Textboxのサブクラスを作成しました。それを処理する適切な方法は何ですか?VB.Netのカスタムテキストボックス

私の会社のVB.Netアプリケーションでは、テキストボックスをGoogleのテキストボックスのように動作させるように求められています。つまり、フォーカスがあるときに青い枠線が必要です。しない。私はすでに、テキストボックスのBorderStyleを 'None'に設定し、フォームのPaintイベント内に適切な矩形を描画することでこれを達成できます。しかし、私が使用するテキストボックスごとに、これを行う必要があります。私たちのアプリケーションにはかなりのものがあります。言うまでもなく、これは苦痛であり、むしろ私が呼ぶことができる1つのコードを持っています。

私は2つの選択肢があると考えました。上記のメソッドを使用する1つのテキストボックスを含むユーザーコントロールを作成するか、またはTextBoxクラスを継承し、この動作標準を作成する独自のクラスを作成できます。私は後者のアプローチを使用することを選択し、OnPaintメソッドをオーバーライドして、私が望む動作を達成しました。しかし今、私はいくつかの新しい落とし穴に遭遇しています。

主な問題は、テキストボックスにフォーカスがあるときに、テキストボックス内のテキストが正しく表示されないことです。テキストは別のフォントを使用し、太字で表示され、ハイライト表示がうまく見えます。テキストボックスのフォーカスが失われた場合、テキストは正しく表示されます。私は、強調表示されたテキストの描画を別々に扱う必要があると考えていますが、私は何をする必要があるのか​​よくわかりません。私はそれをOnPaintメソッドで処理するのですか、それとも別の場所にキャッチする必要がありますか?このアプローチを放棄してユーザーコントロールを行う必要がありますか?

ボーナスに関する質問:カスタムテキストボックスの作成経験がある人は、私が知る必要があるヒントや問題点はありますか?これは私の初めてのカスタムコントロールの作成なので、私は本当にすべてのものを期待するか分からない。

編集:私はUserPaintフラグをtrueに設定しているため、OnPaintをオーバーライドすることができます。私はこれがはっきりしていたと推測していますが、私は徹底したいだけです。

edit2:ここにクラス全体があります。

Imports System.Drawing 

Public Class MyCustomTextBox 
    Inherits TextBox 

    Public Sub New() 
     MyBase.New() 
     Me.BorderStyle = BorderStyle.None 
     SetStyle(ControlStyles.UserPaint, True) 
    End Sub 

    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs) 
     'I want these textboxes to highlight all text by default 
     Me.SelectAll() 
     MyBase.OnGotFocus(e) 
    End Sub 

    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs) 
     Me.SelectionLength = 0 
     MyBase.OnLostFocus(e) 
    End Sub 

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) 
     Dim p As Pen = Nothing 

     'MyBase.OnPaint(e) 

     e.Graphics.FillRectangle(Brushes.White, Me.ClientRectangle) 

     If Me.Focused Then 
     p = New Pen(Brushes.CornflowerBlue) 
     Else 
     p = New Pen(Brushes.Gainsboro) 
     End If 

     e.Graphics.DrawRectangle(p, 0, 0, Me.ClientSize.Width - 1, Me.ClientSize.Height - 1) 
     e.Graphics.DrawString(Me.Text, Me.Font, New SolidBrush(Me.ForeColor), Me.ClientRectangle) 
    End Sub 

End Class 
+0

あなたが行った唯一の変更がOnPaintであるとすると、そのコードを投稿できますか? – Timiz0r

+0

TextBoxは基本的にUserPaintスタイルの有効化をサポートしていません。 –

答えて

2

Hansが述べたように、TextBoxはテキストを描画するときにもOnPaintメソッドを使用しません。

WM_NCPAINTメッセージのコントロールの3D境界にペイントする方法があります。私はそれが完全に無料ちらつきの主張ではないだろう。

Imports System.Runtime.InteropServices 

Public Class TextBoxWithBorder 
    Inherits TextBox 

    Public Const WM_NCPAINT As Integer = &H85 

    <Flags()> _ 
    Private Enum RedrawWindowFlags As UInteger 
    Invalidate = &H1 
    InternalPaint = &H2 
    [Erase] = &H4 
    Validate = &H8 
    NoInternalPaint = &H10 
    NoErase = &H20 
    NoChildren = &H40 
    AllChildren = &H80 
    UpdateNow = &H100 
    EraseNow = &H200 
    Frame = &H400 
    NoFrame = &H800 
    End Enum 

    <DllImport("User32.dll")> _ 
    Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean 
    End Function 

    <DllImport("user32.dll")> _ 
    Private Shared Function RedrawWindow(hWnd As IntPtr, lprcUpdate As IntPtr, hrgnUpdate As IntPtr, flags As RedrawWindowFlags) As Boolean 
    End Function 

    Public Sub New() 
    MyBase.BorderStyle = Windows.Forms.BorderStyle.Fixed3D 
    End Sub 

    Protected Overrides Sub OnResize(e As System.EventArgs) 
    MyBase.OnResize(e) 
    RedrawWindow(Me.Handle, IntPtr.Zero, IntPtr.Zero, RedrawWindowFlags.Frame Or RedrawWindowFlags.UpdateNow Or RedrawWindowFlags.Invalidate) 
    End Sub 

    Protected Overrides Sub WndProc(ByRef m As Message) 
    MyBase.WndProc(m) 

    If m.Msg = WM_NCPAINT Then 
     Dim hDC As IntPtr = GetWindowDC(m.HWnd) 
     Using g As Graphics = Graphics.FromHdc(hDC) 
     If Me.Focused Then 
      g.DrawRectangle(Pens.CornflowerBlue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1)) 
     Else 
      g.DrawRectangle(Pens.Gainsboro, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1)) 
     End If 
     g.DrawRectangle(SystemPens.Window, New Rectangle(1, 1, Me.Width - 3, Me.Height - 3)) 
     End Using 
     ReleaseDC(m.HWnd, hDC) 
    End If 

    End Sub 
End Class 

私は基本的にコントロールが、それは非クライアントエリアだ無効になりますRedrawWindowメッセージを送信するためにさらにonResizeイベントを上書きします。

必要に応じてリファクタリングします。