8

I am making C# / WinForms application. The problem I couldn't solve (yet) is that when I change the SelectedItem of ComboBox programatically, it is changed until the ComboBox loses the focus, after that it "reminds" its value before assigning the SelectedItem. I think that it takes the old value from binding source. When choosing an item using UI the underlying bound object is updated normally but it doesn't so when I'm assigning new value to SelectedItem programatically.

Just for additional info: I am trying to implement "undo", which means I am saving every change somewhere and when Edit>>>Undo I'm reversing all these changes done by user. Interesting thing is that the other controls (TextBoxes, NumericUpDowns) work fine.

Here are the Details:

I have a ComboBox which I bind to the ComboItem object like this:

ComboBox comboBox = new ComboBox();
List<ComboItem> items = new List<ComboItem>();
ComboList comboList = Configuration.ComboList.LoadComboList();

Combo myCombo = comboList.GetCombo(control.MemberName);
if (myCombo != null)
{
    items.Add(new ComboItem(0, "", 0.0, 0.0));
    for (int index = 0; index < myCombo.ComboItems.Count; index++)
    {
        items.Add(myCombo.ComboItems[index]);
    }
}

where Combo and ComboList are custom classes for loading the data from configuration file. Then I set the Display and Value members and also DataSource as well:

comboBox.DisplayMember = "Text";
comboBox.ValueMember = "Key";
comboBox.DataSource = items;

"Text" and "Key" are members of ComboItem class:

public class ComboItem
{
    public int Key { get; set; }
    public string Text { get; set; }
    public double Coef1 { get; set; }
    public double Coef2 { get; set; } 

    public void CopyValues() {...}
    public override bool Equals() {...}
}

Now the problem: when executing undo I check everything needed to have all the cast operations safe and clear and trying to "undo" with this code:

Logger.Info(controls[0], op, "ExecuteUndo");
((ComboBox)controls[0]).Focus();
((ComboBox)controls[0]).SelectedItem = (ComboItem)op.GetOldValue();
Logger.Info(controls[0], "AFTER CHANGE");

Logger is just logging. op object is taken from undo sequence and it gives appropriate value using "GetOldValue()". That code actually IS AFFECTING the UI, but until the control loses its focus. It happens on next undo which should affect other control and thus let this combobox to lose the focus.

I am sure that this happens on comboBox_LostFocus event because first thing I do on this event is Logging and it already shows me the value that SHOULDN'T BE.

Revaz
  • 310
  • 1
  • 2
  • 11
  • Which events of the combobox do you have subsribed? Please show us the code for a SelectedIndexChanged and / or SelectedValueChanged event, if subscribed. – Fischermaen Dec 12 '11 at 09:26
  • So far I would try to use ((ComboBox)controls[0]).SelectedValue = (ComboItem)op.GetOldValue(); instead of SelectedItem. Furthermore, why do you set focus? and pls show us your SelectedXXXChanged eventhandler – Pilgerstorfer Franz Dec 12 '11 at 09:37
  • I've subscribed on comboBox_GotFocus and comboBox_LostFocus at the moment. The purpose of setting focus is to show the user the action of undo, I mean I jump on the control which was changed with undo operation. for textbox and numericUpDown I focus on it and select the text/number in it. If there is different solution I'm ready to try it. "and pls show us your SelectedXXXChanged eventhandler" - I have no such eventhandlers, is that so bad? The binding seems to change without SelectedIndexChanged or SelectedValueChanged when selecting ComboBox item from UI. And SelectedValue didn't help. – Revaz Dec 12 '11 at 10:34
  • This might be useful: I use configuration to bind data to the controls and do it so: `Control.DataBindings.Add(propertyName, bs, key, true, DataSourceUpdateMode.OnPropertyChanged);` where propertyName and key are read from configuration and bs is BindingSource: `BindingSource bs = new BindingSource(); bs.DataSource = type;` – Revaz Dec 12 '11 at 10:42
  • DataBindings can bind on property changed or on validation. Use OnPropertyChanged, if you want an immediate effect. – Olivier Jacot-Descombes Dec 12 '11 at 20:43

1 Answers1

14

I think the problem you are seeing is that the ComboBox is displaying one value, but hasn't written the value to the binding source yet (which doesn't happen until you lose focus).

You can try doing something like this to write the data when an item is selected (assuming there is just the one databinding associated with the ComboBox):

private void comboBox_SelectedIndexChanged(object sender, EventArgs e) {
  comboBox.DataBindings[0].WriteValue();
}

And just to make sure, you either subscribe to this event from the designer, or wire it up manually:

public Form1() {
  InitializeComponent();
  comboBox.SelectedIndexChanged += comboBox_SelectedIndexChanged;
}
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • Exactly! That's what I needed. I needed to write the new value into the binding (in my case that's actually "old" value). Thank you very much. – Revaz Dec 12 '11 at 18:44
  • 7
    Doesn't the need for this kinda make binding redundant? – SteveCav Sep 12 '12 at 02:00
  • It makes binding in windows forms the biggest pain in the ar*e known to man. Having just come from an angularjs project, it is AMAZING that someone managed to make Binding this complicated for devs to implement. – Gumzle Apr 30 '14 at 15:24