Can't leave a bound combobox after deleting its content

I have a combobox (dropdown) that contains something that was loaded from a database. The selectedvalue of the combobox is bound to a typed dataset. The database's column that is displayed by the combobox allows null values. If I select the combobox text and delete it I'm not able to leave the control anymore. I have to enter anything.

I experienced the same behaviour with a textbox that is bound to a money column using a format type in the databinding collection. If I delete its content I'm not able to leave it anymore. I would prefer a behaviour like automatically setting it to 0. I think this would be quite easy by using the "onvalidating" event.

The third scenario I found out is a textbox that is bound to column with a certain length - e.g. 40 chars. If I enter more than 40 chars, I get same behaviour: I can't leave the control. I want to inform the user, that he has to shorten its content - otherwise he has no chance to know, why the system doesn't accept his entries.

Does anybody have any ideas about that?

Thanks a lot!

[1062 byte] By [TAS] at [2008-2-15]
# 1

For the first item, the best solution is to add another item to the DataTable that maps "" to DBNull.Value and then set the ComboBox style to DropDownList. In the absense of that, you have to deal with other issue such as what happens when the user types in a value that isn't in your list (rather than just blanks it).

For the second item, you'll need to handle the Parse event to convert "" to 0:


Binding b = new Binding("Text", this, "Money", true);

b.Parse += delegate(object pSender, ConvertEventArgs pArgs)
{
pArgs.Value = (string.IsNullOrEmpty(pArgs.Value as string) ? 0 : pArgs.Value);
};

this.textBox1.DataBindings.Add(b);

For the last issue, there are a couple of ways you can solve this. First, you can hook the TextChanged event on the TextBox and do validation as the user types into the TextBox. You can also hook the BindingComplete and set an error using the ErrorProvider as shown below. In addition, in the BindingCompleteEvent, you can set bArgs.Cancel to false to allow the user to leave the text box even with a bad value.


private void Form1_Load(object sender, EventArgs e)
{
TextBox tb1 = new TextBox();
TextBox tb2 = new TextBox();
ErrorProvider ep = new ErrorProvider(this);

tb1.Location = new Point(10, 10);
tb2.Location = new Point(10, 35);

Binding b = new Binding("Text", this, "Value", true);

b.BindingComplete += delegate(object bSender, BindingCompleteEventArgs bArgs)
{
if ((bArgs.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate) && (bArgs.BindingCompleteState == BindingCompleteState.Exception))
{
ep.SetError(tb1, bArgs.Exception.Message);
}
else
{
ep.SetError(tb1, null);
}
};

tb1.DataBindings.Add(b);

this.Controls.Add(tb1);
this.Controls.Add(tb2);
}

private string _value=string.Empty;

public string Value
{
get { return _value; }
set
{
if (value.Length > 10)
{
throw new Exception("Value must be 10 characters or less");
}
_value = value;
}
}

Joe

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 2
Thanks a lot for these ideas.

Solutions for 2 and 3 work fine for me but I still can't solve problem 1...

I changed the combobox to "dropdownlist" and added one row to the lookup-datasource that contains a DBNULL in the valuemember column and a "" in the displaymember column.
So the dropdownlist contains its regular items + one empty item, but I'm still not able to leave the combobox if I select the empty item.

I checked my typed datasets, but the column allows dbnull.

Any further ideas?

Thank you!
David

TAS at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 3

Unfortunately, this is not as easy as I'd like it to be and will be specific to your data model. It's quite likely you're data model won't allow DBNull.Value for the "ValueMember" (primary ID), so you'll end up needing to do something slightly more complex such as both adding a null value to your data source and hooking format and parse events. The sample code below puts an "empty" Employee in the Northwind Employees table and displays the employee for the currently selected order (in Northwind, the Orders table has a FK to the Employees table). I put a "null" employee in the Employees table and then hook Format/Parse events to translate the null employee to DBNull.Value. In order to get this to work, you'll have to manually setup binding to the ComboBox selected value (it will need to happen after you add the "null" row). Note that the employeesBindingSource is bound to the employees table and the ordersBindingSource is bound to the Orders table.

Joe


DataRowView drv = (this.employeesBindingSource.AddNew() as DataRowView);
drv["LastName"] = "[None]";
drv["FirstName"] = string.Empty;
drv["EmployeeID"] = -1;
drv.EndEdit();

DataView dv = (this.employeesBindingSource.List as DataView);
dv.Sort = "LastName ASC";

this.employeeIDComboBox.DataSource = this.employeesBindingSource;
this.employeeIDComboBox.DisplayMember = "LastName";
this.employeeIDComboBox.ValueMember = "EmployeeID";

Binding b = new Binding("SelectedValue", this.ordersBindingSource, "EmployeeID", true);
this.employeeIDComboBox.DataBindings.Add(b);

b.Format += delegate(object fSender, ConvertEventArgs fArgs)
{
ComboBox cb = (b.Control as ComboBox);

if ((fArgs.Value is DBNull) || (fArgs.Value == null))
{
fArgs.Value = -1;
}
};

b.Parse += delegate(object pSender, ConvertEventArgs pArgs)
{
ComboBox cb = (b.Control as ComboBox);

if ((null != cb) && (string.IsNullOrEmpty(cb.Text)))
{
pArgs.Value = DBNull.Value;
}
};

JoeStegman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 4

Thanks a lot for this proposal. It works fine for me! I could get it to work just by using parse and format events without the need to manually add a empty entry by code and set the bindings.

I added one entry to my lookup table with a value of -1. Parse and Format events just doing the trick to convert DBNull -> -1 and backwards.

After that I just had to solve one final problem: if the user is selecting the "" value by pressing "DEL", the SelectedValue is "nothing" instead of "-1". So I use the validating event to manually set SelectedValue to -1. Now it works exactly as I wanted to.

After that I'm suprised that there's no easier way, because I think this topic isn't this special...

Thanks again.

TAS at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...
# 5

For the second issue, this seems to work:


TextBox1.DataBindings("text").NullValue = ""

RobertRFreeman at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Data Controls and Databinding...