RESOLVED - Disable some items in a combobox
Hi,
Is it possible to disable some items in a combobox?
Depending on the current mode that my application is in, certain items need to be enabled or disabled.
I know that I could remove the items and rebuild the combobox but in this case I think that by showing the items greyed out it gives the user feedback as to what mode they are in and what options would be available to them if they decided to switch modes.
Any help appreciated.
Re: Disable some items in a combobox
You don't need to remove the items so much as filter them out. If you bind your combobox to a table for example, you can include a field that indicates what mode (modes) each item is meant for. Then simply filter.
Re: Disable some items in a combobox
Thanks for the quick reply:thumb:
Either I didn't explain myself very well or I do not understand your reply. Probably the latter.
Say I have a combobox with the following items in it
Apple
Orange
Pear
Dog
Cat
Cow
Depending on the mode that the user has selected elsewhere in the program I want to allow them to select certain items from the combobox.
In "fruits" mode they can select Apple, Orange or Pear. In "animals" mode they can select Dog, Cat or Cow. In "All" mode they can select any of the items from the combobox.
But, so that they can see what they are missing when in "fruits" mode, I want to display the animal names grayed out in the combobox.
Re: Disable some items in a combobox
The only way I can think of is if you draw the items yourself by changing the DrawMode property of the combobox to OwnerFixed or OwnerVariable (not sure what the difference is, can someone confirm?) and then use your own DrawItem event handler like this:
vb.net Code:
'Declared at class level so it can be used in mutliple procedures
Dim DisabledList As New List(Of String)
'Here is our form load event, I'm just adding an item to the list of disabled items here
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DisabledList.Add("number 1")
End Sub
'Here is the event that actually draws each item
Private Sub ComboBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles ComboBox1.DrawItem
'Create our font that will be used for drawing each item
Dim ItemFont As New Font("Arial", 8, FontStyle.Regular)
'This DirectCast is not completely necessary but it makes it easier to work with the current item we are drawing
Dim CurrentItem As String = DirectCast(sender, ComboBox).Items(e.Index)
'Draw the background for the item
e.Graphics.FillRectangle(New SolidBrush(Color.White), e.Bounds)
'If the item is in the disabled list then we draw the item with a Gray brush
If DisabledList.Contains(CurrentItem) Then
e.Graphics.DrawString(CurrentItem, ItemFont, New SolidBrush(Color.Gray), e.Bounds.X, e.Bounds.Y)
Else
'The item was not in the disabled list so we draw it with a black brush as normal
e.Graphics.DrawString(CurrentItem, ItemFont, Brushes.Black, e.Bounds.X, e.Bounds.Y)
End If
End Sub
Obviously that code still leaves a lot to be desired (the blue background that should appear when the mouse goes over each item doesnt work using my example above) but hopefully you get the idea :)
Basically in the draw routine it checks to see if the item is in the DisabledList list and if so then it uses a gray coloured brush to create the text, if not then it uses a black brush. So the idea being that when you want to 'disable' an item you just add it to the DisabledList list.
Note that this assumes you are just populating the combobox with strings and not classes that override the ToString method (I've never tried that with a combobox but i assume it can be done)
Hope that helps!
Re: Disable some items in a combobox
Quote:
Originally Posted by chris128
The only way I can think of is if you draw the items yourself by changing the DrawMode property of the combobox to OwnerFixed or OwnerVariable (not sure what the difference is, can someone confirm?) and then use your own DrawItem event handler like this:
vb.net Code:
'Declared at class level so it can be used in mutliple procedures
Dim DisabledList As New List(Of String)
'Here is our form load event, I'm just adding an item to the list of disabled items here
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DisabledList.Add("number 1")
End Sub
'Here is the event that actually draws each item
Private Sub ComboBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles ComboBox1.DrawItem
'Create our font that will be used for drawing each item
Dim ItemFont As New Font("Arial", 8, FontStyle.Regular)
'This DirectCast is not completely necessary but it makes it easier to work with the current item we are drawing
Dim CurrentItem As String = DirectCast(sender, ComboBox).Items(e.Index)
'Draw the background for the item
e.Graphics.FillRectangle(New SolidBrush(Color.White), e.Bounds)
'If the item is in the disabled list then we draw the item with a Gray brush
If DisabledList.Contains(CurrentItem) Then
e.Graphics.DrawString(CurrentItem, ItemFont, New SolidBrush(Color.Gray), e.Bounds.X, e.Bounds.Y)
Else
'The item was not in the disabled list so we draw it with a black brush as normal
e.Graphics.DrawString(CurrentItem, ItemFont, Brushes.Black, e.Bounds.X, e.Bounds.Y)
End If
End Sub
Obviously that code still leaves a lot to be desired (the blue background that should appear when the mouse goes over each item doesnt work using my example above) but hopefully you get the idea :)
Basically in the draw routine it checks to see if the item is in the DisabledList list and if so then it uses a gray coloured brush to create the text, if not then it uses a black brush. So the idea being that when you want to 'disable' an item you just add it to the DisabledList list.
Note that this assumes you are just populating the combobox with strings and not classes that override the ToString method (I've never tried that with a combobox but i assume it can be done)
Hope that helps!
When you create a new brush, be sure to clean up the resources so errors don't happen:
Code:
'Declared at class level so it can be used in mutliple procedures
Dim DisabledList As New List(Of String)
'Here is our form load event, I'm just adding an item to the list of disabled items here
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DisabledList.Add("number 1")
End Sub
'Here is the event that actually draws each item
Private Sub ComboBox1_DrawItem(ByVal sender As Object, ByVal e As DrawItemEventArgs) Handles ComboBox1.DrawItem
'Create our font that will be used for drawing each item
Dim ItemFont As New Font("Arial", 8, FontStyle.Regular)
'This DirectCast is not completely necessary but it makes it easier to work with the current item we are drawing
Dim CurrentItem As String = DirectCast(sender, ComboBox).Items(e.Index)
'Draw the background for the item
Using w As New SolidBrush(Color.White)
e.Graphics.FillRectangle(w, e.Bounds)
End Using
'If the item is in the disabled list then we draw the item with a Gray brush
If DisabledList.Contains(CurrentItem) Then
Using b As New SolidBrush(Color.Gray)
e.Graphics.DrawString(CurrentItem, ItemFont, b, e.Bounds.X, e.Bounds.Y)
End Using
Else
'The item was not in the disabled list so we draw it with a black brush as normal
e.Graphics.DrawString(CurrentItem, ItemFont, Brushes.Black, e.Bounds.X, e.Bounds.Y)
End If
End Sub
Re: Disable some items in a combobox
Re: Disable some items in a combobox
Many thanks to all who have contributed.
That looks like it should work very nicely for me.
Re: RESOLVED - Disable some items in a combobox
No problem :)
If you do need to make it so that the highlight box appears when the user's mouse goes over each item I think you need to do something with the e.DrawFocusRectangle method inside the DrawItem event handler but I've not tested it.
Re: RESOLVED - Disable some items in a combobox
instead of creating a font in the drawitem handler, I would use ComboBox1.font instead. Otherwise the font selection you make at design time will have no effect on the combobox.
Re: RESOLVED - Disable some items in a combobox
Good point!
Thanks for the suggestion.
I just need to get the mouseover highlight working and I am there.
Re: RESOLVED - Disable some items in a combobox
Damn there's always something wrong with my code examples! :P
Re: RESOLVED - Disable some items in a combobox
That was certainly not meant to be a criticism.
I always rate helpful posts and yours, and others who assisted me here, were helpful.
Mind you, if you do come up with a solution to the highlight problem I would appreciate that also :)
Re: RESOLVED - Disable some items in a combobox
This might help:
Code:
Dim br As Brush = Brushes.White
' change brush color if item is selected
If (e.State And DrawItemState.Selected) = DrawItemState.Selected Then
br = Brushes.White
Else
br = Brushes.Black
End If
You'd use code similar to that when drawing the background for the current item
Re: RESOLVED - Disable some items in a combobox
Thanks, I'll give that a go.
Re: RESOLVED - Disable some items in a combobox
I would wrap this up in a class to make it easier to work with and modify.
If you add a new class and add in this code, you can then use ComboBoxEx from the toolbox instead of using a regular combobox and having to add all this code to your form.
Also, this will expose the DisabledItems property in the property grid, so you can easily add items at design time that you want to be grayed out.
Code:
Imports System.ComponentModel
Public Class ComboBoxEx
Inherits ComboBox
Private _DisabledItems As New List(Of String)
Public Sub New()
Me.DrawMode = Windows.Forms.DrawMode.OwnerDrawFixed
End Sub
Private Function IsItemDisabled(ByVal Index As Integer) As Boolean
Return _DisabledItems.Contains(Me.Items(Index).ToString)
End Function
Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
Dim TextToDraw As String = Me.Items(e.Index).ToString
e.DrawBackground()
e.DrawFocusRectangle()
'If the item is in the disabled list then we draw the item with a Gray brush
If IsItemDisabled(e.Index) Then
Using b As New SolidBrush(Color.Gray)
e.Graphics.DrawString(TextToDraw, Me.Font, b, e.Bounds.X, e.Bounds.Y)
End Using
Else
Using b As New SolidBrush(e.ForeColor)
e.Graphics.DrawString(TextToDraw, Me.Font, b, e.Bounds.X, e.Bounds.Y)
End Using
End If
MyBase.OnDrawItem(e)
End Sub
<Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design", "System.Drawing.Design.UITypeEditor, System.Drawing")> _
Public Property DisabledItems() As List(Of String)
Get
Return _DisabledItems
End Get
Set(ByVal value As List(Of String))
_DisabledItems = value
End Set
End Property
End Class
Re: RESOLVED - Disable some items in a combobox
That works very well - Thank You
The only remaining issue that I have is stopping the user from selecting the disabled items.
The way that I have implemented at the moment is to do a check in the SelectedIndexChanged event to see if the user has clicked on a disabled item. If they have then I just increment the SelectedIndex value.
This works but is not as elegant as I would like.
I have found some complicated C# code that intercepts the highlight changed but do not know where to start with converting it to VB.
Any ideas?
Re: RESOLVED - Disable some items in a combobox
To do that, you will probably want to handle some key press events to, because you will want to know if the user is scrolling the list with arrow keys, up or down so you can jump the disabled items in the correct direction.
Re: RESOLVED - Disable some items in a combobox
Re: RESOLVED - Disable some items in a combobox
kleinma,
I have then ComboBoxEx working, but I am having trouble creating a DLL with VB 2010. Is this caused by 2010 and not having 2008? Any help would be appreciated