Установить флажок 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. Я нашел наиболее актуальную информацию здесь:
- Как установить ключевой текст в XP: http://www.ageektrapped.com/blog/the-missing-net-1-cue-banners-in-windows-forms-em_setcuebanner-text-prompt/
- Как установить ключевой текст в 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 и вам нужно, чтобы поля со списком были доступны только для чтения, но при этом отображали текст подсказки, вот что вы можете сделать:
- Создайте поле со списком и используйте DropDownStyle по умолчанию, "DropDown"
- Обработайте событие KeyPress для поля со списком и в этом методе сообщите ему, что событие было обработано так:
e.Handled = True.
Это предотвратит ввод текста. - Создайте пустой 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