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

Very strange ComboBox databinding problem
TecToc
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
Ivo Leitao
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];
JuanManuelC
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()));
}
}
AnilGopu
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
licheca
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
Herwin Grauel
Probably you are seeing the odd behaviour because SelectionChanged() is called before calling the base method. Try moving SelectionChanged() after the base.OnDataSourceChanged call.
PLCweaver
kxp
Thanks a lot for the explanation and your help.