1

I am creating a custom control that inherits from ComboBox. I need to detect when a Item is added to the ComboBox to perform my own checks. It doesn't matter if it's C# or Vb.NET, but I don't know how to do it.

I tried all the things I found across the internet, including this thread, but the link in the answer is offline and I didn't manage to guess what should I do.

For example, this code in Vb.net:

Public Sub SomeFunc() Handles Items.CollectionChanged
    '....
End Sub

It says that Items property is not defined WithEvents.

The control is not using a BindingSource. I need the control to perform a custom action when an Item is added. Items are added directly into the .Items property with:

customComboBox.Items.Add("item");

Can it be done?

SysDragon
  • 9,692
  • 15
  • 60
  • 89
  • Is this WPF or WinForms? Can you show some code? How are items being added to the ComboBox? – eddie_cat Jul 15 '14 at 15:05
  • @Savanna Winforms, edited – SysDragon Jul 15 '14 at 15:06
  • In the link you provided, it is suggested to subscribe to the CollectionChanged event on the ComboBox's Items collection. Have you tried this? Please post your code so we can see where you are getting stuck. – eddie_cat Jul 15 '14 at 15:07
  • You will need to also subclass Items/ItemCollection. There is no `CollectionChanged` event unless/until you rewrite it as an Observable Collection (which is what the linked article is talking about for WPF). – Ňɏssa Pøngjǣrdenlarp Jul 15 '14 at 15:12
  • @Plutonix How can I do that on Winforms? – SysDragon Jul 15 '14 at 15:13
  • 1
    `how can I do that` with great difficulty. I started to subclass the LV Items collection and gave up. Remember, especially with the CBO and LB, those are not just strings but can be class objects in the collection, so you are taking on a lot of work. – Ňɏssa Pøngjǣrdenlarp Jul 15 '14 at 15:21
  • @Plutonix I was hoping there was a simpler workaround to known when a item is added. Thanks – SysDragon Jul 15 '14 at 15:22
  • 2
    I was having a look for a solution to this. Using reflection I was able to change the internal items collection of the ComboBox (private field `itemCollection`) but the `ComobBox.ObjectCollection` does not let you override the Add method (although the this[index] is virtual). I think I am about ready to give up but just in case someone wants to go further then [this might be of interest](http://stackoverflow.com/a/9684888/340045). Using a similar approach someone might override the Add method of the collection. – Ben Jul 15 '14 at 17:05

4 Answers4

6

I think the best approach would be to listen for the native ComboBox messages:

Don't be fooled by the word STRING, they are all fired whenever you add, insert or delete an item. So when the list is cleared.

Public Class UIComboBox
    Inherits ComboBox

    Private Sub NotifyAdded(index As Integer)
    End Sub

    Private Sub NotifyCleared()
    End Sub

    Private Sub NotifyInserted(index As Integer)
    End Sub

    Private Sub NotifyRemoved(index As Integer)
    End Sub

    Protected Overrides Sub WndProc(ByRef m As Message)
        Select Case m.Msg
            Case CB_ADDSTRING
                MyBase.WndProc(m)
                Dim index As Integer = (Me.Items.Count - 1)
                Me.NotifyAdded(index)
                Exit Select
            Case CB_DELETESTRING
                MyBase.WndProc(m)
                Dim index As Integer = m.WParam.ToInt32()
                Me.NotifyRemoved(index)
                Exit Select
            Case CB_INSERTSTRING
                MyBase.WndProc(m)
                Dim index As Integer = m.WParam.ToInt32()
                Me.NotifyAdded(If((index > -1), index, (Me.Items.Count - 1)))
                Exit Select
            Case CB_RESETCONTENT
                MyBase.WndProc(m)
                Me.NotifyCleared()
                Exit Select
            Case Else
                MyBase.WndProc(m)
                Exit Select
        End Select
    End Sub

    Private Const CB_ADDSTRING As Integer = &H143
    Private Const CB_DELETESTRING As Integer = &H144
    Private Const CB_INSERTSTRING As Integer = 330
    Private Const CB_RESETCONTENT As Integer = &H14B

End Class
Bjørn-Roger Kringsjå
  • 9,849
  • 6
  • 36
  • 64
  • Worked like a charm, thanks. I just modified the method to remove the `Exit Select`, put the `MyBase.WndProc(m)` at the beggining and some other minor changes. – SysDragon Jul 16 '14 at 06:59
1

If your ComboBox is backed by a BindingSource, then you could listen for the AddingItem event and handle it accordingly.

Chris Hinton
  • 866
  • 5
  • 15
  • It is not using a BindingSource, sadly. I need the control to perform a custom action when an Item is added. Items are added directly into the `control.Items` property. – SysDragon Jul 15 '14 at 15:19
0

You are in control of when items are added to a ComboBox. So, there are no events fired when this happens.

You are the one who adds items to the ComboBox. It's not an external executable that do this, it's your code. So, you can ensure that all your adds are done via a function AddItem(item As Object) {...} that you should handle the logic you need to do when items are being added inside it. So, no need for events.

Hesham Eraqi
  • 2,444
  • 4
  • 23
  • 45
  • didn't downvote but can you please explain this `You are in control of`? – Sid M Jul 15 '14 at 15:12
  • 1
    Sorry for the brief answer. I meant that you are the one who adds items to the ComboBox. It's not an external executable that do this, it's your code. So, you can ensure that all your adds are done via a function AddItem(item As Object) {...} that you should handle the logic you need to do when items are being added inside it. So, no need for events. – Hesham Eraqi Jul 15 '14 at 15:18
  • I need the event because the control has to perform a custom action when an Item is added. And that have to be done without expecting the final programmer to add it, but to use the control directly. – SysDragon Jul 15 '14 at 15:25
  • Two solutions: - Create your own control API for adding items `CustomAdd`, inside this function you should call the normal ComboBox `Add` function + the logic you wanted the event for. - Override the ComboBox `Add` method. – Hesham Eraqi Jul 15 '14 at 15:35
  • 1
    The issue with the second option is you will really have to override the Items.Add method, as mentioned by SysDragon in the comments above... ComboBox doesn't have an Add method, it's Combobox.Items.Add. – eddie_cat Jul 15 '14 at 15:37
0

I was recently struggling with the same question and found the documentation and other web posts lacking. At its heart a Windows Forms ComboBox is two controls in one. A compact ListBox and a TextBox. I wanted to detect when a user had typed a new entry into the TextBox that wasn't contained in the Items collection so that the new item could be processed and possibly added to the list of items to be selected.

The control doesn't define an event covering this case directly and the TextChanged event is far too granular.

What I found was the following logic in a Leave event handler to detect a potential new item that isn't on the list.

void cb_Leave(object sender, EventArgs e) {
    if (cb.SelectedIndex < 0 && string.IsNullOrEmpty(cb.Text)) {
        // The Text represents the potential new item provided by the user
        // Insert validation, value generation, etc. here
        // If the proposed text becomes a new item, add it to the list
        ListItemType newItem = new ListItemType(cb.Text);
        cb.Items.Add(newItem);

        // And don't forget to select the new item so that the
        // SelectedIndex and SelectedItem are updated to reflect the addition
        cb.SelectedItem = newItem;
    }

}

If you are simply using string values as your list item, then the newItem above is simply the cb.Text.