Jonathan Sumilang
Jonathan Sumilang

Reputation: 37

Can I add a button inside a combobox?

just wanna know if I can do something like an add button inside a combo box, in which its function is to add a new value for the combo box

enter image description here

Upvotes: 0

Views: 5642

Answers (2)

Nyerguds
Nyerguds

Reputation: 5629

You can add an "Add new..." dummy item at the top or bottom of the available list in the combobox. When you detect it is selected, you give a popup box for the new item's creation. When the user confirms the creation in the dialog, you then refresh the combobox contents, and change the selection in the combobox to that newly created item. If the user cancelled the creation dialog, you select the first item in the list that is not the "Add new..." item, or null if no other items are available, to prevent ending up on the popup-giving item again and getting stuck in a loop.

This method's drawback is that you can add but not edit or remove, though. Imagine if you add a new measurement unit this way but mistyped something in it, then it's still permanently added to the list and you can't change it.

You may consider making an actual management dialog for the contents of the combobox instead, and just put that in some menu. Then the user has better control over the measurement units that will show up in the list.

Then, when that management dialog is closed, you store the selected option in your current UI in a temp variable, then replace the contents of the combobox with your new list, and then look through the new list to see if that previously-selected option is in there, and if so, select it.

Heck... you can just put your units manager as that dummy item. Make a "Manage units..." item at the bottom of the list instead of just an "Add new..." and just make it open the management dialog.

Of course I have no idea what kind of backing system this UI is built against... does it work with files? A database? All I can do is offer suggestions based on what I see in the screenshot.


The way I did it was to keep my list of items as private variable. For convenience's sake, I'll just use a private List<String> for it here, but in reality you can put any type in there as long as it exposes a .ToString() method that shows the string you want to show.

Then, I made sure that the dummy item was always added to the end, and made the selection change method check if the new selected index is larger than the internal list, in which case the only item that could possibly be selected is the "Add new" one.

So, the combobox handling would be like this:

private const String CREATENEW = "Create new...";
private List<String> measurementUnits; // Fill this up somehow.
private String lastSelectedUnit;
private Boolean loading = false;

public MyForm()
{
    this.InitializeComponent();
    // Fill up the 'measurementUnits' list somehow here.

    // ...

    // Add items to list
    RefreshMeasurementUnits();
}

public Boolean RefreshMeasurementUnits()
{
    Boolean wasLoading = loading;
    loading = true;
    try
    {
        // Last selected actual item.
        String selectedItem = this.lastSelectedUnit;
        Int32 selected = -1;
        for (Int32 i = 0; i < this.measurementUnits.Count; i++)
        {
            String curItem = this.measurementUnits[i];
            // could be adapted if the units in the list are not just simple 'String' class
            if (selectedItem == curItem)
                selected = i;
            this.cmbMeasurementUnits.Items.Add(curItem);
        }
        this.cmbMeasurementUnits.Items.Add(CREATENEW);
        if (selected != -1)
            this.cmbMeasurementUnits.SelectedIndex = selected;
        // Returns true if an item was selected.
        return selected != -1;
    }
    finally { loading = wasLoading; }
}

private void cmbMeasurementUnits_SelectedIndexChanged(Object sender, EventArgs e)
{
    if (loading)
        return;
    // Detect if selected item is the last one.
    if (this.cmbMeasurementUnits.SelectedIndex < this.measurementUnits.Count)
    {
        // store last selected item
        this.lastSelectedUnit = this.cmbMeasurementUnits.SelectedItem as String;
        // exit if the item is not the last one.
        return;
    }
    // Code to add new item here. Only executed if the item is the last one.
    // This should open a dialog that manipulates the contents of the
    // 'measurementUnits' list.
    // If an item was specifically added, this code can change the 'lastSelectedUnit'
    // variable to ensure that it will be the selected item after the refresh.

    // ...

    // Refresh the items list using the 'measurementUnits' list.
    Boolean hasSelection = RefreshMeasurementUnits();
    // if auto-reselect failed, ensure that the selected item is NOT the last one.
    if (!hasSelection)
        cmbMeasurementUnits.SelectedIndex = measurementUnits.Count > 0 ? 0 : -1;
}

Upvotes: 2

oldcoder
oldcoder

Reputation: 342

It is possible but you would have to build your own custom control from scratch to do this.

Instead the way I do this is to check if the value is in the list when leaving the combo, and if not offer the opportunity to add it in place. This is usually better as the user just types and it works without the need to use buttons which are not part of the standard control set.

Personally I use a specialised combo that has a NotInList event, but you could use the Validating event instead. The advantage of the extra event is that you can cancel the leave if the add fails by simply setting Cancel to true.

Edit

As per your request below, here is an example of how you could handle this problem using the Validating event:

private void MyComboValidating(object sender, CancelEventArgs e)
{
    // Entry is not in the list    
    if (myCombo.Modified && myCombo.Text.Length > 0 && myCombo.SelectedIndex == -1) 
    {
        // AddEntry is a method you would write that shows a dialog to allow the user to
        // add the entry and returns true if the entry is successfully
        //  added or false otherwise 
        if (!AddEntry()) 
        {
            e.Cancel = args.Cancel;
        {
    }
}

Obviously you would replace myCombo with the name of your combobox control. MyComboValidating is the event handler created by the designer or which you create yourself. If it has a different name in your form, you can simply put the code inside the handler whatever its name is...

I hope that this is both clear and helpful.

Upvotes: 1

Related Questions