Skip Navigation LinksHome > View Post

DataBinding on SelectedIndexChanged in WinForms.NET

When binding to a ComboBox in WinForms, the value in your underlying object only gets set when focus is lost. What if you want to perform some action on the SelectedIndexChanged which depends on what you have selected (to update another part of your form for example)?

You could always write your code in the SelectedIndexChanged event to get the value manually, but then you loose the power of databinding and also of code reuse.

Solution

This post describes a solution to the problem by using an extender component. You might have read my post on Databinding and Nullable types in WinForms.NET. If you haven't and wonder what an extender component is, follow the link from that article :D

This time the extender looks pretty much the same, but extends the ComboBox and has a property called BindOnSelectedIndexChanged.

Since my previous post about extenders goes into a bit more detail, I will simply list the code for this extender below:


[ProvideProperty("BindOnSelectedIndexChanged", typeof(ComboBox))]
public partial class DropDownBinder : Component, IExtenderProvider
{
    private Dictionary<Control, Boolean> _bindable = new Dictionary<Control, bool>();

    ...

        
    /// <summary>
    /// This function loops through the bindings on the control
    /// and writes the value to the underlying object.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void BindOnSelectedIndexChanged(object sender, EventArgs e)
    {
        ComboBox dropDown = (ComboBox)sender;
        foreach (Binding binding in dropDown.DataBindings)
        {
            binding.WriteValue();
        }
    }

    /// <summary>
    /// This is the extender property.
    /// It is actually a method because it takes the control.
    /// </summary>
    /// <param name="control"></param>
    [DefaultValue(false),     Category("Data")]
    public bool GetBindOnSelectedIndexChanged(Control control)
    {
        bool nullableBinding = false;
        _bindable.TryGetValue(control, out nullableBinding);
        return nullableBinding;
    }

    /// <summary>
    /// This is the extender property.
    /// It is actually a method because it takes the control.
    /// </summary>
    /// <param name="control"></param>
    /// <param name="nullable"></param>
    public void SetBindOnSelectedIndexChanged(Control control, bool bindOnSelectedIndexChanged)
    {
        if (_bindable.ContainsKey(control))
            _bindable[control] = bindOnSelectedIndexChanged;
        else
            _bindable.Add(control, bindOnSelectedIndexChanged);
        if (bindOnSelectedIndexChanged)
        {
            ComboBox dropDown = (ComboBox)control;
            dropDown.SelectedIndexChanged += new EventHandler(BindOnSelectedIndexChanged);
        }
    }
    
}

If you now set the BindOnSelectedIndexChanged property on your ComboBox control, the value will be available in your underlying object on SelectedIndexChanged:

BindOnSelectedIndexChanged UPDATE: If you wonder why I do not unhook the event if bindOnSelectedIndexChanged, the reason is simply that the setting of the property happens at design time. This means that the SetBindOnSelectedIndexChanged method is only called once. If you want to be on the safe side, you could simply change the SetBindOnSelectedIndexChanged method to the one below:


    /// </summary>
    /// <param name="control"></param>
    /// <param name="nullable"></param>
    public void SetBindOnSelectedIndexChanged(Control control, bool bindOnSelectedIndexChanged)
    {
        if (_bindable.ContainsKey(control))
            _bindable[control] = bindOnSelectedIndexChanged;
        else
            _bindable.Add(control, bindOnSelectedIndexChanged);
        ComboBox dropDown = (ComboBox)control;
        if (bindOnSelectedIndexChanged)
        {
            dropDown.SelectedIndexChanged += new EventHandler(BindOnSelectedIndexChanged);
        }
        else
        {
            dropDown.SelectedIndexChanged -= new EventHandler(BindOnSelectedIndexChanged);
        }
    }

Tags: WinForms.NET

 
Bruusi Post By Bruusi
10:50 PM
22 Jun 2006

» Next Post: Run dialog shortcuts
« Previous Post: SSIS Xmlify Data Flow Task

Comments are closed for this post.

Posted by Inferis @ 23 Jun 2006 12:17 AM
Why is there no code to handle the bindOnSelectedIndexChanged == false case? If I understand correctly, the code above won't allow to cancel the binding behaviour?

Or is this not so much of a problem since this is a design time thing?

Posted by Bruusi @ 23 Jun 2006 6:01 AM
Hi Inferis,

the reason for why I have omitted it is exactly that it is a design time setup. The SetBindOnSelectedIndexChanged function will only be called once. You could however unhook the event to be on the safe side.

I think I will update the post, as a lot of people have been asking the same question!

Thanks very much for your interest!

© 2005 - 2014 Josh Twist - All Rights Reserved.