【问题标题】:custom textboxes in VB.NetVB.Net 中的自定义文本框
【发布时间】:2011-11-29 19:12:08
【问题描述】:

tldr - 制作了 Textbox 的子类,当它有焦点时,文本看起来很奇怪。正确的处理方法是什么?

对于我公司的 VB.Net 应用程序,我被要求让我们的文本框表现得像 Google 的文本框,即当它们有焦点时需要在它们周围有一个蓝色边框,当它们有焦点时它们需要有一个灰色边框不是。我已经可以通过将文本框的 BorderStyle 设置为“None”,然后在表单的 Paint 事件中绘制适当的矩形来完成此操作。但是,我必须为我使用的每一个文本框都这样做。我们的应用程序有很多。不用说,这很痛苦,我宁愿有一段可以调用的代码。

所以我认为我有两个选择;我可以制作一个包含使用上述方法的单个文本框的用户控件,或者我可以编写自己的类,该类继承自 TextBox 类并使这种行为成为标准。我选择使用后一种方法,并且通过覆盖 OnPaint 方法,我已经实现了所需的行为。但现在我遇到了一些新的陷阱。

我遇到的主要问题是当文本框获得焦点时,文本框中的文本无法正确呈现。文本采用不同的字体,显示为粗体,并且突出显示看起来很不稳定。如果文本框失去焦点,则文本看起来正确。我怀疑我需要以不同的方式处理突出显示文本的绘图,但我不确定我需要做什么。我是在 OnPaint 方法中处理它还是需要在其他地方捕获它?我是否需要完全放弃这种方法而只进行用户控制?

额外问题:对于有制作自定义文本框经验的任何人,我是否需要了解任何提示或陷阱?这是我第一次制作自定义控件,所以我真的不知道会发生什么。

编辑:忘了提到我能够覆盖 OnPaint,因为我将 UserPaint 标志设置为 true。我猜这很明显,但我只想彻底。

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

【问题讨论】:

  • 假设 OnPaint 是您所做的唯一更改,您可以发布该代码吗?
  • TextBox 根本不支持开启 UserPaint 样式。

标签: vb.net custom-controls


【解决方案1】:

正如 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

我重写了 OnResize 事件以发送 RedrawWindow 消息,这基本上使控件无效它的非客户区。

根据需要重构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-18
    • 2013-03-02
    • 2013-06-29
    相关资源
    最近更新 更多