Very strange ComboBox databinding problem

Hi,

this problem really drives me nuts. I have a custom ComboBox, which derives from the normal ComboBox control. I'm setting the DataSource of the ComboBox in my code to a DataTable and also set DisplayMember and ValueMember. So, the binding in general works fine, but here's the odd part:

Depending on what is selected I color the background of the ComboBox differently. To achieve this effect when the DataSource changed i overwrite the OnDataSourceChanged method:


      
     protected override void OnDataSourceChanged(EventArgs e)
        {
            SelectionChanged();
            base.OnDataSourceChanged(e);
        }

 


The selction changed method does all the coloring and here is what really buzzes me. When the method is triggered, I evalute this.Text and this.SelectedValue. However, both of them are empty after OnDataSourceChanged is entered. Anyways, when I set a debug point at the code that checks if this.Text is empty, this.Text is indeed "", however, when I now explore all the properties and fields of "this" in the debugger, this.Text suddenly changes to the expected value. If I continue to run the code the value and coloring shows up just fine. However, when I let it run through without setting the debug point, this.Text stays empty and it gets colored incorrectly since the text actually shows up in the control afterwards.

Any ideas


Answer this question

Very strange ComboBox databinding problem

  • orac123456789

    ahhh ... I found my error ...
    I changed the DataSource after the InitializeComponent() of the hosting form. It works when I do it in the Load method of the form. Can someone tell me what the difference is
    Anyways, thanks a lot for all your help

  • Timpie

    hm, now I'm calling base.OnDataSourceChanged first but still have the very same problem What else could be wrong

  • Kent Chenery

    OnDataSourceChanged() is called after the data source is set but before the ComboBox is filled with the data source items.  As Durstin has pointed out, by calling the base implementation first, you will ensure the ComboBox is filled prior to your code being called.  Note that the values of this.Text and this.SelectedValue will be invalid until after you step past base.OnDataSourceChanged().  Possibly the issue you are seeing is you are stepping past base.OnDataSourceChanged() causing the values to then appear.

    Note that calls to this.Text and this.SelectedValue prior to base.OnDataSourceChanged() will result in exceptions that are caught and handled by ComboBox.

    Joe

  • Amit Tzafrir

    The ComboBox Text does not get set until it's handle is created and this doesn't happen until the Form is made visible (after the Form constructor) - so any checks on the ComboBox.Text prior to Form.Load will return string.Empty.

    Also, is your data source filled in InitializeComponent()   If not, then this will also cause problems as there will be no SelectedValue or Text value.

    Joe


  • Olivier Robin

    Nope, as I indicated, now I fill it in the Form Load method and everything works.. so, problem  solved ;)
    Thanks a lot for the explanation and your help.

  • Dhanasu

    Without replicating your specific problem, I'm guessing...but, when you change the DataSource for a combobox, the selection gets wiped out. You need to reset it. 

    Probably you are seeing the odd behaviour because SelectionChanged() is called before calling the base method. Try moving SelectionChanged() after the base.OnDataSourceChanged call.

  • NickNotYet

    Can you post a repro of the issue   The sample below works fine on Beta 2 bits so there may be more to it than what you've described.

    Joe


    public class Form1 : Form
    {
     private Button button1;
     private MyComboBox myComboBox1;

     public Form1()
     {
      this.button1 = new Button();
      this.myComboBox1 = new MyComboBox();

      this.button1.Location = new System.Drawing.Point(171, 10);
      this.button1.Name = "button1";
      this.button1.Size = new System.Drawing.Size(75, 23);
      this.button1.Text = "Set DS";
      this.button1.Click += delegate
      {
       ChangeDataSource();
      };

      this.myComboBox1.FormattingEnabled = true;
      this.myComboBox1.Location = new System.Drawing.Point(12, 12);
      this.myComboBox1.Name = "myComboBox1";
      this.myComboBox1.Size = new System.Drawing.Size(153, 21);

      this.Controls.Add(this.myComboBox1);
      this.Controls.Add(this.button1);

      this.Load += delegate
      {
       ChangeDataSource();
      };
     }

     private void ChangeDataSource()
     {
      DataTable dt = new DataTable();
      dt.Columns.Add("ID", typeof(int));
      dt.Columns.Add("Name");

      int seconds = DateTime.Now.Second + 1;

      for (int idx = seconds; idx >= 0; idx--)
      {
       dt.Rows.Add(idx, idx.ToString());
      }

      this.myComboBox1.DisplayMember = "Name";
      this.myComboBox1.ValueMember = "ID";
      this.myComboBox1.DataSource = dt;
     }
    }

    class MyComboBox : ComboBox
    {
     Random _rand = new Random();

     protected override void OnDataSourceChanged(EventArgs e)
     {
      base.OnDataSourceChanged(e);

      Color color = Color.FromArgb(_rand.Next(255), _rand.Next(255), _rand.Next(255));
      this.BackColor = color;

      System.Diagnostics.Debug.WriteLine("Text: " + this.Text);
      System.Diagnostics.Debug.WriteLine("SelectedValue: " + ((null == this.SelectedValue) "(NULL)" : this.SelectedValue.ToString()));
     }
    }

     


  • KCtin

    hmm... now that's interesting .. your sample works for me as well ... here's my ComboBox class:


    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Drawing;
    using System.ComponentModel;

    namespace Vms.Sam.Client.CommonControls
    {
        class CustomComboBox : ComboBox
        {
            #region Fields
            private Color _goodBackColor = Color.LightGreen;
            private Color _badBackColor = Color.LightPink;
            private Color _badNotRequiredColor = Color.LightBlue;
            private Color _blankBackColor = System.Drawing.SystemColors.Window;
            private bool _isGood;
            private bool _isRequired;
            #endregion

            #region Properties
            [Browsable(false)]
            public override Color BackColor
            {
                get { return base.BackColor; }
                set { }
            }

            [Browsable(false)]
            public override Color ForeColor
            {
                get { return base.ForeColor; }
                set { }
            }

            public bool IsRequired
            {
                get { return _isRequired; }
                set
                {
                    _isRequired = value;
                    SetColors();
                }
            }

            [Browsable(false)]
            public bool IsGood
            {
                get { return _isGood; }
            }
            #endregion

            public CustomComboBox()
            {
                SetColors();
            }

            private void SetColors()
            {
                if (_isRequired == true && this.Enabled == true && _isGood == false)
                {
                    base.BackColor = _badBackColor;
                }
                else if (_isRequired == true && this.Enabled == true && _isGood == true)
                {
                    base.BackColor = _goodBackColor;
                }
                else
                {
                    base.BackColor = SystemColors.Window;
                }
                base.Invalidate();
            }

            private void SelectionChanged()
            {
                if (_isRequired == true)
                {
                    if (this.Text.ToString().Length == 0 && this.Enabled == true)
                    {
                        base.BackColor = _badBackColor;
                        _isGood = false;
                    }
                    else if (this.Enabled)
                    {
                        base.BackColor = _goodBackColor;
                        _isGood = true;
                    }
                    else if (!this.Enabled)
                    {
                        base.BackColor = SystemColors.Control;
                        _isGood = true;
                    }
                }
            }
           
            protected override void OnSelectedIndexChanged(EventArgs e)
            {
                base.OnSelectedIndexChanged(e);
                SelectionChanged();
            }

            protected override void OnSelectedValueChanged(EventArgs e)
            {
                base.OnSelectedValueChanged(e);
                SelectionChanged();
            }

            protected override void OnEnabledChanged(EventArgs e)
            {
                base.OnEnabledChanged(e);
                SelectionChanged();
            }

            protected override void OnDataSourceChanged(EventArgs e)
            {
                base.OnDataSourceChanged(e);
                SelectionChanged();
            }

            protected override void OnTextChanged(EventArgs e)
            {
                base.OnTextChanged(e);
                SelectionChanged();
            }
        }
    }

     


    Here I set the DataSource of the ComboBox:


                cbCoop.DisplayMember = "CoopName";
                cbCoop.ValueMember = "CoopId";
                cbCoop.DataSource = ObjectStore.Account.Coops.Tables[0];

     



  • Very strange ComboBox databinding problem