Пользовательское текстовое поле с водяными знаками ведет себя странно - PullRequest
3 голосов
/ 18 марта 2009

РЕШЕНИЕ:

Благодаря Патрику ниже я реорганизовал версию C # CodeProject в версию VB.NET, которая работает для меня. Надеюсь, это поможет и вам, ребята:

Partial Public Class WatermarkedTextBox
    Inherits TextBox

    Private _waterMarkColor As Color = Color.LightGray
    Public Property WaterMarkColor() As Color
        Get
            Return _waterMarkColor
        End Get
        Set(ByVal value As Color)
            _waterMarkColor = value
        End Set
    End Property
    Private _waterMarkText As String = "Watermark"
    Public Property WaterMarkText() As String
        Get
            Return _waterMarkText
        End Get
        Set(ByVal value As String)
            _waterMarkText = value
        End Set
    End Property
    Sub New()

    End Sub
    Protected Overloads Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()
    End Sub
    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        MyBase.WndProc(m)
        Const WM_PAINT As Integer = &HF
        If m.Msg = WM_PAINT Then
            If Text.Length <> 0 Then
                Return
            End If
            Using g As Graphics = Me.CreateGraphics
                g.DrawString(WaterMarkText, Me.Font, New SolidBrush(WaterMarkColor), 0, 0)
            End Using
        End If
    End Sub
    Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
        MyBase.OnTextChanged(e)
        Invalidate()
    End Sub
    Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
        MyBase.OnLostFocus(e)
        Invalidate()
    End Sub
    Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs)
        MyBase.OnFontChanged(e)
        Invalidate()
    End Sub
    Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
        '' added so the watermark is not cleared until text is entered
        MyBase.OnGotFocus(e)
        Invalidate()
    End Sub
End Class

Я создаю приложение для киоска, и чтобы сделать его эстетически приятным, я решил добавить текстовое поле с водяными знаками в качестве полей ввода. Я нашел этот проект в CodeProject , преобразовал его в VB.NET и вставил в мое приложение. Это работает, в том смысле, что это водяные знаки и просто их очищает, но когда я иду, чтобы ввести текст, это происходит:

Empty:

alt text

Заполненный:

alt text

Так что в основном это не очистка всего водяного знака, а просто пространство, выделенное для высоты текстового поля по умолчанию. Вот преобразованный код:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing


Partial Public Class WatermarkedTextBox
    Inherits TextBox
    Private oldFont As Font = Nothing
    Private waterMarkTextEnabled As Boolean = False

#Region "Attributes"
    Private _waterMarkColor As Color = Color.LightGray
    Public Property WaterMarkColor() As Color
        Get
            Return _waterMarkColor
        End Get
        Set(ByVal value As Color)
            _waterMarkColor = value
            Invalidate()
        End Set
    End Property
    Private _waterMarkText As String = "Water Mark"
    Public Property WaterMarkText() As String
        Get
            Return _waterMarkText
        End Get
        Set(ByVal value As String)
            _waterMarkText = value
            Invalidate()
        End Set
    End Property
#End Region

    Public Sub New()
        JoinEvents(True)
    End Sub  
    Protected Overloads Overrides Sub OnCreateControl()
        MyBase.OnCreateControl()
        WaterMark_Toggle(Nothing, Nothing)
    End Sub
    Protected Overloads Overrides Sub OnPaint(ByVal args As PaintEventArgs)
        'Dim drawFont As New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit)
        Dim drawFont As New Font("Arial", 28, FontStyle.Bold) 'New System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit)
        Dim drawBrush As New SolidBrush(WaterMarkColor)
        args.Graphics.DrawString((If(waterMarkTextEnabled, WaterMarkText, Text)), drawFont, drawBrush, New PointF(0.0F, 0.0F))
        MyBase.OnPaint(args)
    End Sub

    Private Sub JoinEvents(ByVal join As Boolean)
        If join Then
            AddHandler Me.TextChanged, AddressOf WaterMark_Toggle
            AddHandler Me.LostFocus, AddressOf Me.WaterMark_Toggle
            AddHandler Me.FontChanged, AddressOf Me.WaterMark_FontChanged
        End If
    End Sub

    Private Sub WaterMark_Toggle(ByVal sender As Object, ByVal args As EventArgs)
        If Me.Text.Length <= 0 Then
            EnableWaterMark()
        Else
            DisableWaterMark()
        End If
    End Sub

    Private Sub EnableWaterMark()
        oldFont = New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit)
        Me.SetStyle(ControlStyles.UserPaint, True)
        Me.waterMarkTextEnabled = True
        Refresh()
    End Sub

    Private Sub DisableWaterMark()
        Me.waterMarkTextEnabled = False
        Me.SetStyle(ControlStyles.UserPaint, False)
        If oldFont IsNot Nothing Then
            Me.Font = New System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit)
        End If
    End Sub

    Private Sub WaterMark_FontChanged(ByVal sender As Object, ByVal args As EventArgs)
        If waterMarkTextEnabled Then
            oldFont = New System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style, Font.Unit)
            Refresh()
        End If
    End Sub
End Class

Я попытался заставить класс использовать мой установленный размер шрифта в событии OnPaint, но безуспешно. Есть ли что-то еще, что мне не хватает, что делает это более трудным, чем должно быть?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 18 марта 2009

Вам просто не хватает обновления в конце подпункта DisableWaterMark:

Private Sub DisableWaterMark()
    Me.waterMarkTextEnabled = False
    Me.SetStyle(ControlStyles.UserPaint, False)
    If oldFont IsNot Nothing Then
        Me.Font = New System.Drawing.Font(oldFont.FontFamily, oldFont.Size, oldFont.Style, oldFont.Unit)
    End If
    Refresh()
End Sub

EDIT:

Вместо использования стиля элемента управления UserPaint вы можете обрабатывать сообщение WM_PAINT в WndProc и печатать водяной знак только в том случае, если текст пустой. Результат в основном такой же, хотя.

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    MyBase.WndProc(m)
    Const WM_PAINT As Integer = &HF
    If m.Msg = WM_PAINT Then
        If Text.Length <> 0 Then
            Return
        End If
        Using g As Graphics = Me.CreateGraphics
            g.DrawString("Water Mark", Me.Font, Brushes.LightGray, 0, 0)
        End Using
    End If
End Sub

Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
    MyBase.OnTextChanged(e)
    Invalidate()
End Sub

Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
    MyBase.OnLostFocus(e)
    Invalidate()
End Sub

Protected Overrides Sub OnFontChanged(ByVal e As System.EventArgs)
    MyBase.OnFontChanged(e)
    Invalidate()
End Sub
0 голосов
/ 18 марта 2009

есть что-то здесь и здесь , которое может вам помочь

...