views:

334

answers:

2

I created a simple example with data binding (unfortunately we have a similar case in our system). I created a funky combo box:

public class FunkyComboBox : ComboBox
    {
        private object currentValue = null;

        public FunkyComboBox()
        {
            if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
                this.Items.Add("Other...");
        }

        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            if (!this.Text.StartsWith("Other") && currentValue != this.SelectedItem)
            {
                currentValue = this.SelectedItem;
                BindingManagerBase bindingManager = DataManager;
                base.OnSelectedIndexChanged(e);
            }
        }

        protected override void OnSelectionChangeCommitted(EventArgs e)
        {
            string itemAsStr = this.SelectedItem != null ? SelectedItem.ToString() : "";
            if (itemAsStr.StartsWith("Other"))
            {
                string newItem = "item" + this.Items.Count;
                if (!Items.Contains(newItem))
                {
                    Items.Add(newItem);
                }
                SelectedItem = newItem;
            }
            else
            {
                OnSelectedIndexChanged(e); //forces a selectedIndexChanged event to be thrown
                base.OnSelectionChangeCommitted(e);
            }
        }
    }

which adds new items when you click Other (in our system it opens a form where you can query database etc). Then I have a simple data object:

public class MyClass
{
    private string value;
    public string MyData
    {
        get{ return value;}
        set{ this.value = value;}
    }
}

And a test form with 2 controls bound to this object (some designer code removed):

public partial class Form1 : Form
{
    MyClass myObj = new MyClass();
    public Form1()
    {
        InitializeComponent();
        myObj.MyData = "Nothing";
        myClassBindingSource.DataSource = myObj;
    }

    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.textBox1 = new System.Windows.Forms.TextBox();
        this.myClassBindingSource = new System.Windows.Forms.BindingSource(this.components);
        this.funkyComboBox1 = new DataBindingTests.FunkyComboBox();
        ((System.ComponentModel.ISupportInitialize)(this.myClassBindingSource)).BeginInit();
        this.SuspendLayout();
        // 
        // textBox1
        // 
        this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.myClassBindingSource, "MyData", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));

        // 
        // myClassBindingSource
        // 
        this.myClassBindingSource.DataSource = typeof(DataBindingTests.MyClass);
        // 
        // funkyComboBox1
        // 
        this.funkyComboBox1.DataBindings.Add(new System.Windows.Forms.Binding("SelectedItem", this.myClassBindingSource, "MyData", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
        this.funkyComboBox1.DataBindings.Add(new System.Windows.Forms.Binding("SelectedValue", this.myClassBindingSource, "MyData", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
        // 
        // Form1
        // 
        this.Controls.Add(this.textBox1);
        this.Controls.Add(this.funkyComboBox1);
        ((System.ComponentModel.ISupportInitialize)(this.myClassBindingSource)).EndInit();
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    private FunkyComboBox funkyComboBox1;
    private System.Windows.Forms.BindingSource myClassBindingSource;
    private System.Windows.Forms.TextBox textBox1;
}

If you run this code and start playing with the combo box, you will notice that the edit box changes only if you click on it. After every change a null value is set to my object and the text box is cleared. How can I make it set the correct value after every change?

+2  A: 

I know this question is pretty old and by now you may have found an answer to your problem. I'm not really sure why the ComboBox databinding behaves this way, but I have found a workaround. It seems as though the databing doesn't work correctly if you don't use a datasource for your ComboBox's values.

I made a few minor chages to FunkyComboBox and it now works as expected.

public class FunkyComboBox : ComboBox
{
    private object currentValue = null;
    private List<string> innerItems = new List<string>();

    public FunkyComboBox()
    {
        if (LicenseManager.UsageMode == LicenseUsageMode.Runtime)
            innerItems.Add("Other...");

        this.DataSource = innerItems;
    }

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        if (!this.Text.StartsWith("Other") && currentValue != this.SelectedItem)
        {
            currentValue = this.SelectedItem;
            BindingManagerBase bindingManager = DataManager;
            base.OnSelectedIndexChanged(e);
        }
    }

    protected override void OnSelectionChangeCommitted(EventArgs e)
    {
        string itemAsStr = this.SelectedItem != null ? SelectedItem.ToString() : "";
        if (itemAsStr.StartsWith("Other"))
        {
            string newItem = "item" + this.Items.Count;                
            if(!innerItems.Contains(newItem))
            {
                innerItems.Add(newItem);
                this.RefreshItems();
            } SelectedItem = newItem;
        }
        else
        {
            OnSelectedIndexChanged(e);
            //forces a selectedIndexChanged event to be thrown              
            base.OnSelectionChangeCommitted(e);
        }
    }
}
Joepro
A: 

It seems to be a bug with the base ComboBox as well, it is not possible to get this binding source malarky work correctly.

Grzenio