views:

696

answers:

2

I have a form databound to a customer object, and one of the fields is a nullable int representing a "type". This is displayed as a combobox, and the combobox is bound to the "Types" table.

When a customer with a null type is loaded into the form's datasource, the combo box displays no value, but then upon clicking it you must select a value. The form/combobox will never let you change back to a blank item (to represent "null" on the customer object).

I don't want "dummy rows" in the database, and currently do this by adding a dummy object, and nulling it out in a submit event (not clean!).

Is it possible to do this cleanly, keeping with the nullable primary key?

A: 

The datasource which is used to bind to the Type combo, could have 1 more entry with NULL value in it.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TypeID   Name
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1        Business
2        Government
-1       NULL

You could store -1 for Customer who doesn't have a type (if it is allowed that a customer need not have a type).

shahkalpesh
I don't want -1 in my database. I want null.
TheSoftwareJedi
Dont store -1 in the DB. If the user chooses blank item from the DB (hence the selectedItem's value will be -1) - store null in DB if thats the case
shahkalpesh
A: 

Additional links and resources concerning nullable databinding:

I've been told and so far it has panned out, that you should have a layer of business objects in between your database datasource and your UI where you could just add an item as shahkalpesh recommends without concern of it going into the database.

Jez Humble has some information on binding nullable types at the bottom of this post and in comments Where it suggests binding to nullable types is doable if "you explicitly set the DataSourceUpdateMode to DataSourceUpdateMode.OnPropertyChanged".

Another article on databinding Nullable types: The Joy of Code - Databinding and Nullable types in WinForms.NET

Maybe this code for binding a nullable DateTimePicker could help you find addditional solutions for this or other nullable issues.

Also check out Dan Hannan for the source of where I came up with my extension method.

/// <summary>
 /// From BReusable
 /// </summary>
 /// <param name="dtp"></param>
 /// <param name="dataSource"></param>
 /// <param name="valueMember"></param>
 /// <remarks>With help from Dan Hanan at http://blogs.interknowlogy.com/danhanan/archive/2007/01/21/10847.aspx&lt;/remarks&gt;
 public static void BindNullableValue(this DateTimePicker dateTimePicker, BindingSource dataSource, String valueMember,bool showCheckBox)
 {
  var binding = new Binding("Value", dataSource, valueMember, true);

  //OBJECT PROPERTY --> CONTROL VALUE
  binding.Format += new ConvertEventHandler((sender, e) =>
  {
   Binding b = sender as Binding;

   if (b != null)
   {
    DateTimePicker dtp = (binding.Control as DateTimePicker);
    if (dtp != null)
    {
     if (e.Value == null)
     {

      dtp.ShowCheckBox = showCheckBox;
      dtp.Checked = false;

      // have to set e.Value to SOMETHING, since it's coming in as NULL
      // if i set to DateTime.Today, and that's DIFFERENT than the control's current
      // value, then it triggers a CHANGE to the value, which CHECKS the box (not ok)
      // the trick - set e.Value to whatever value the control currently has. 
      // This does NOT cause a CHANGE, and the checkbox stays OFF.

      e.Value = dtp.Value;

     }
     else
     {
      dtp.ShowCheckBox = showCheckBox;
      dtp.Checked = true;
      // leave e.Value unchanged - it's not null, so the DTP is fine with it.
     }

    }

   }
  });
  // CONTROL VALUE --> OBJECT PROPERTY
  binding.Parse += new ConvertEventHandler((sender, e) =>
  {
   // e.value is the formatted value coming from the control. 
   // we change it to be the value we want to stuff in the object.
   Binding b = sender as Binding;

   if (b != null)
   {
    DateTimePicker dtp = (b.Control as DateTimePicker);
    if (dtp != null)
    {
     if (dtp.Checked == false)
     {
      dtp.ShowCheckBox = showCheckBox;
      dtp.Checked = false;
      e.Value = (Nullable<DateTime>)null;
     }
     else
     {
      DateTime val = Convert.ToDateTime(e.Value);
      e.Value = val;
     }
    }
   }
  });
  dateTimePicker.DataBindings.Add(binding);

 }
Maslow