Установить флажок ComboBox в Windows XP

Я обновляю проект VB.net, в который необходимо добавить баннеры с метками в текстовые поля и комбинированные списки только для чтения (DropDownStyle=DropDownList). Машина, на которой я работаю, - Windows 7. Я добавляю текст подсказки в класс, который расширяет поле со списком и добавляет свойство текста подсказки. Вот как текст подсказки добавляется в выпадающий список:

 '"Me" refers to a combobox that has been extended to include a Cue Text property
 SendMessage(New HandleRef(Me, Me.Handle), CB_SETCUEBANNER, IntPtr.Zero, _cueText)

Приведенный выше код взят из этого блога: http://www.aaronlerch.com/blog/page/7/, который находится на C#; Я перевел это на VB. Я пробовал другие похожие варианты, которые я нашел в другом месте, все с тем же результатом: он отлично работает для текстовых полей и комбинированных списков, когда я запускаю программу в Windows 7; это работает только для текстовых полей в Windows XP.

Я прочитал множество комментариев на разных форумах о том, как выбрать визуальные стили и отключить языки Восточной Азии и сложные сценарии. Я сделал все это, но до сих пор не получил его работать на XP.

Кто-нибудь получил кий-баннеры для комбо-боксов для работы на XP?

1 ответ

Решение

Используя различные посты в блогах и на форумах, я создал класс, который расширяет элемент управления ComboBox и реализует свойство CueText, которое работает в Windows 7 и XP. Я нашел наиболее актуальную информацию здесь:

  1. Как установить ключевой текст в XP: http://www.ageektrapped.com/blog/the-missing-net-1-cue-banners-in-windows-forms-em_setcuebanner-text-prompt/
  2. Как установить ключевой текст в Windows 7: http://www.aaronlerch.com/blog/2007/12/01/watermarked-edit-controls/

Короче говоря, Windows 7 и XP устанавливают текст баннера метки немного по-другому, поэтому вам нужно проверить, в какой операционной системе работает программа, а затем соответствующим образом обработать текст метки. Вам нужно использовать EM_SETCUEBANNER As Integer = &H1501 для XP и CB_SETCUEBANNER As UInteger = &H1703 для Windows 7. Вам также нужно выделить текстовую часть поля со списком, если приложение работает на XP. Вы можете увидеть детали в коде ниже. Чтобы выяснить, какая ОС работает, см. Статьи MS KB 304289 (VB) или 304283 (C#). (Я бы опубликовал ссылки, но у меня недостаточно очков репутации, чтобы опубликовать более двух.)

Одно предостережение в том, что это не будет работать на XP, если поля со списком доступны только для чтения (DropDownStyle = DropDownList). Windows 7, кажется, работает в любом случае. Если ваше приложение должно работать на XP и вам нужно, чтобы поля со списком были доступны только для чтения, но при этом отображали текст подсказки, вот что вы можете сделать:

  1. Создайте поле со списком и используйте DropDownStyle по умолчанию, "DropDown"
  2. Обработайте событие KeyPress для поля со списком и в этом методе сообщите ему, что событие было обработано так: e.Handled = True. Это предотвратит ввод текста.
  3. Создайте пустой ContextMenuStrip с помощью панели инструментов в представлении конструктора, щелкните поле со списком, просмотрите его свойства и установите для его ContextMenuStrip значение, которое вы только что создали. Это ничего не даст, когда пользователь щелкнет правой кнопкой мыши в поле со списком, чтобы они не могли вставить в него текст.

Вот код VB для класса, который наследует элемент управления ComboBox и добавляет свойство CueText, которое работает для XP и 7. Единственное, что вам нужно сделать, это выяснить, какая ОС работает:

Imports System.ComponentModel
Imports System.Runtime.InteropServices

Public Class CueComboBox
Inherits ComboBox

' Occurs when the CueText property value changes.
Public Event CueTextChanged As EventHandler

'Windows XP
Private Shared EM_SETCUEBANNER As Integer = &H1501
'Windows 7
Private Shared CB_SETCUEBANNER As UInteger = &H1703

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal        wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
End Function

<DllImport("user32.dll")> _
Private Shared Function GetComboBoxInfo(ByVal hwnd As IntPtr, ByRef pcbi As COMBOBOXINFO) As Boolean
End Function

<StructLayout(LayoutKind.Sequential)> _
Private Structure COMBOBOXINFO
    Public cbSize As Integer
    Public rcItem As RECT
    Public rcButton As RECT
    Public stateButton As IntPtr
    Public hwndCombo As IntPtr
    Public hwndItem As IntPtr
    Public hwndList As IntPtr
End Structure

<StructLayout(LayoutKind.Sequential)> _
Private Structure RECT
    Public left As Integer
    Public top As Integer
    Public right As Integer
    Public bottom As Integer
End Structure

Private Shared Function GetComboBoxInfo(ByVal control As Control) As COMBOBOXINFO
    Dim info As New COMBOBOXINFO()
    'a combobox is made up of three controls, a button, a list and textbox;
    'we want the textbox
    info.cbSize = Marshal.SizeOf(info)
    GetComboBoxInfo(control.Handle, info)
    Return info
End Function


Private _cueText As String = [String].Empty

' Gets or sets the text that will display as a cue to the user.
<Description("The text value to be displayed as a cue to the user.")> _
<Category("Appearance")> <DefaultValue("")> <Localizable(True)> _
Public Property CueText() As String
    Get
        Return _cueText
    End Get
    Set(ByVal value As String)
        If value Is Nothing Then
            value = [String].Empty
        End If

        If Not _cueText.Equals(value, StringComparison.CurrentCulture) Then
            _cueText = value
            UpdateCue()
            OnCueTextChanged(EventArgs.Empty)
        End If
    End Set
End Property

<EditorBrowsable(EditorBrowsableState.Advanced)> _
Protected Overridable Sub OnCueTextChanged(ByVal e As EventArgs)
    RaiseEvent CueTextChanged(Me, e)
End Sub


Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
    UpdateCue()
    MyBase.OnHandleCreated(e)
End Sub


Private Sub UpdateCue()
    ' If the handle isn't yet created, this will be called when it is created
    If Me.IsHandleCreated Then
        ' Windows XP sets the cue banner differently than Windows 7
        If Form1.OPERATING_SYSTEM = "Windows XP" Then
            Dim info As COMBOBOXINFO = GetComboBoxInfo(Me)
            SendMessage(info.hwndItem, EM_SETCUEBANNER, 0, _cueText)
        Else
            SendMessage(New HandleRef(Me, Me.Handle), CB_SETCUEBANNER, IntPtr.Zero, _cueText)
        End If
    End If
End Sub

End Class
Другие вопросы по тегам