personalizzato caselle di testo in VB.Net

tldr Fatto una sottoclasse di una casella di testo, il testo sembra strano quando è attivo. Qual è il modo corretto di gestire?

Della mia azienda VB.Net applicazione, mi è stato chiesto di rendere le nostre caselle di testo si comportano come Google, caselle di testo, cioè hanno bisogno di avere un blu-ish bordo intorno a loro, quando hanno la messa a fuoco e un grigio-ish confine quando non lo sono. Ho già possibile eseguire questa impostazione di un textbox BorderStyle ‘None’), poi il disegno appropriato rettangolo all’interno di un modulo evento Paint. Tuttavia, devo fare questo per ogni singola casella di testo che uso io. E la nostra applicazione ha un bel paio di loro. Inutile dire che questo è un dolore, e io preferirei avere un pezzo di codice che mi possono chiamare.

Così ho pensato che ho due opzioni; mi può fare un controllo utente che contiene una casella di testo singola che utilizza il metodo di cui sopra, o sono in grado di scrivere la mia classe che eredita dalla classe TextBox e rende questo comportamento standard. Ho scelto di utilizzare l’approccio di quest’ultimo, e tramite l’override del metodo OnPaint ho raggiunto il comportamento desiderato. Ma ora sto incontrando alcune nuove insidie.

Il principale problema che sto avendo è che il testo all’interno della casella di testo non viene visualizzata correttamente quando la casella di testo ha il focus. Il testo assume un diverso tipo di carattere viene visualizzato in grassetto, ed evidenziando sembra traballante. Se la textbox perde la messa a fuoco, il testo è corretto. Ho il sospetto che ho bisogno di gestire il disegno per il testo evidenziato in modo diverso, ma io non sono sicuro di quello che devo fare. Posso gestire in OnPaint metodo o devo prenderlo da qualche altra parte? Devo abbandonare questo approccio del tutto, e basta fare un controllo utente?

Domanda Bonus: per chi ha esperienza di come rendere le caselle di testo, ci sono consigli o trucchi che ho bisogno di sapere? Questa è la mia prima volta facendo un controllo personalizzato, quindi non so davvero quello che tutti si aspettano.

edit: ho dimenticato di dire che io sono in grado di ignorare OnPaint perchè ho impostato il UserPaint flag a true. Sto indovinando questo era ovvio, ma voglio solo essere approfondita.

edit2: Ecco la classe nella sua interezza.

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
  • Supponendo OnPaint è l’unica modifica che hai fatto, puoi postare il codice?
  • TextBox fondamentalmente non supporta l’accensione del UserPaint stile.
InformationsquelleAutor MattM | 2011-11-29



One Reply
  1. 2

    Come Hans accennato, la casella di testo non utilizzare il metodo OnPaint quando trae il suo testo.

    Un modo per farlo è dipingere il bordo 3D del controllo in WM_NCPAINT messaggio. Io non pretendiamo è completamente flicker free:

    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

    Sovrascrivere l’evento OnResize per inviare il RedrawWindow messaggio, che in pratica rende il controllo invalidare è area non client.

    Refactoring come necessario.

Lascia un commento