• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 283
  • Last Modified:

Binding Manager Add.New() causing hangups on bound DateTime column (null value?)


I have a simple form bound to a data table.  The code was copied from a program that works, and everything about the new form works except the "Add New" functionality.

Clicking the "Add New" button executes this code:
 
     myBindingManager.AddNew();

The behavior I see is that:

    The bound controls do not automatically reset to blank values like they should.
     A row is added (myBindingManager.Count is incremented) but changing the position of the binding manager
          to that row (myBindingManager.Position ++) doesn't work; it refuses to advance to the new row.

After fooling around a bit, I discovered that the hangup seems to be that I have added a DataTimePicker control and bound it to a DateTime type column:

myDateTimePickerControl.DataBindings.Add (new Binding("Value", dsMyDataSet, "tablename.datetimecolumnname"));

When changing the binding manager position to move through the rows everything works fine if there is a value in the column, but if it is null (as it is when a new record is added) the binding manager chokes.

1. How can I set up my binding to handle null values in the columns, and
2. Which column types besides DateTime will probably be set to null on an Add.New()?
0
FrancineTaylor
Asked:
FrancineTaylor
  • 7
  • 5
  • 2
2 Solutions
 
Alexandre SimõesManager / Technology SpecialistCommented:

Hi!

If you're using the framework 2.0 the Binding object have some new properties.
One of the is on one constructor overload and is named NullValue. This will change the value to a default whenever the source value is null.

If you're still on FW 1.0 or 1.1 then I believe this isn't as easy.

http://www.codeproject.com/cs/miscctrl/Nullable_DateTimePicker.asp
http://www.dotnet247.com/247reference/msgs/32/162933.aspx
http://blogs.duncanmackenzie.net/duncanma/archive/2003/02/28.aspx

Alex :p
0
 
sumixCommented:

Maybe you should consider setting default values for datetime column
    dsMyDataSet.tablename.Columns["datetimecolumnname"].DefaultValue = DateTime.Now;

Every column will have a null value after AddNew method if it doesn't have a default value set. The behavior you mention is also determined by boolean columns.
0
 
FrancineTaylorAuthor Commented:
I like your solution, sumix, and it will solve the immediate problem for those columns which can be forced to accept a date, but in the case of Date Fired for employee I can't put a default value in, nulls have to be allowed.

I need a way to detect whether the is a null value in the column or not.  If there is a null, I can set the datetimepicker to a blank value.  But I need to be able to intercept the values going into to bound controls.  I vaguely recall that there is such a mechanism, but I haven't been able to track it down.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
Alexandre SimõesManager / Technology SpecialistCommented:

The default DateTimePicker doesn't support blank (null) values...
You'll have to make one that supports (as one on the links I gave you) or set a default value...

Alex :p
0
 
Alexandre SimõesManager / Technology SpecialistCommented:

I would like to comment this:
"But I need to be able to intercept the values going into to bound controls."

Based on what I previously said, even if you in some sort of way, had a way to intercept the values between the datasource and the bound controls, what would you do?
     - Set them to a certain value if null? (seems like a default value behavior)
     - Leave them null? (same as nothing)
     - What else could be an option?...


Alex :p
0
 
sumixCommented:

Binding class has Format event which is fired when data from the source is pushed into bound control. You can intercept this event and set a value in the control, even the value from the datatable is null:
   
   Binding b = new Binding("Value", dsMyDataSet, "tablename.datetimecolumnname");
   b.Format += new ConvertEventHandler(b_Format);
   myDateTimePickerControl.DataBindings.Add(b);

   private void b_Format(object sender, ConvertEventArgs e)
  {
     if (e.Value == System.DBNull.Value)
      {
            e.Value = DateTime.Now;
            Console.WriteLine("Null value");
      }
   }

  Note that this will only change the value of the control, not the one int the table.

  Also, Parse event occurs when data is pulled from the control into the data source.

0
 
Alexandre SimõesManager / Technology SpecialistCommented:

As I see it, the Format event isn't an option either...
He still can't show an empty DateTimePicker... it must have a value...

We can use that event when we needed to format data that come from the DB into readonly textboxes...
If the textbox is editable it won't format it on validate...
Anyway, I usually use a custom textbox control that formats the data for presentation (currency format for ex...)

Alex
0
 
FrancineTaylorAuthor Commented:
Actually, showing an empty datetime isn't too difficult.  A little unwieldly, perhaps.

Here is the method I use:

static public void SetDateTimePicker(DateTimePicker pdtp, Boolean pbSetToNull)
{
      if (pbSetToNull)
      {
            pdtp.Format = DateTimePickerFormat.Custom;
            pdtp.CustomFormat = " ";
      }
      else
      {
            pdtp.Format = DateTimePickerFormat.Short;
      }
}

In my form_load, I have this code:

        SetDateTimePicker(myDateTimePicker, true);

Then, I create this event method:

      private void myDateTimePicker_ValueChanged(object sender, System.EventArgs e)
      {
            SetDateTimePicker(myDateTimePicker, false);
      }

Datepickers start out with blank values, then when the user selects a value, the artificially imposed "blankness" is removed.

0
 
Alexandre SimõesManager / Technology SpecialistCommented:

Althogh it may work you'll have to code that every time you have to implement such feature.
Wouldn't it be wiser to create your custom control and just reuse it?...

Alex :p
0
 
FrancineTaylorAuthor Commented:
You have a good point, but it's still a hard call to make.  Some of the considerations:

I like to design my standalone applications so that they are easily portable to web applications.  I'm hoping (tho I haven't yet had time to do the research) that Parse and Format are available for web controls.

As you mentioned, I'd have to code the Parse and Format into every application.  That would be a bit tedious.

If I went with a custom control, I'd need to include that control in every project, which means there would be multiple copies of it.  If changes were made, I'd either have to have multiple versions of the control, or I'd have to recompile and retest with every application.

And the biggest consideration: I haven't yet gotten a workable modified datetimepicker control that will compile on my computer.  I pulled down the one from Code Project, but when I unzipped it and tried to compile it told me the NullableDateTimePicker.resx file was missing.
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
I'll comment your consederation...

1)
"I like to design my standalone applications so that they are easily portable to web applications.  I'm hoping (tho I haven't yet had time to do the research) that Parse and Format are available for web controls."
- That's the spirit... althogh you're not acting right about it.
     The support for null dates is just a missing functionality (one within undreds) on the .net controls (DateTimePicker on this case).
     If what you want is to provide a null date to the UI, your business layer is right, you just don't have a capable UI control to handle it.
     On these cases we do or customise a control to fit owr needs.
     I'm sure that when you port your app to web you'll find other limitation on the web controls that you didn't had on the windows version. What will you do? Change the business logic and mess the windows application? NO!! You'll have to create or chage a webcontrol that fits your needs.

2)
"As you mentioned, I'd have to code the Parse and Format into every application.  That would be a bit tedious."
- You bet!

3)
"If I went with a custom control, I'd need to include that control in every project, which means there would be multiple copies of it.  If changes were made, I'd either have to have multiple versions of the control, or I'd have to recompile and retest with every application."
- Compiling the application along with the new version of the control will do... what's wrong with it?
     Think about what you have now... imagine that you have to change something on that way of doing it? How many form will you have to change the very same code?
     With a custom control you'll only have to change the code in one place...

4)
"I haven't yet gotten a workable modified datetimepicker control that will compile on my computer.  I pulled down the one from Code Project, but when I unzipped it and tried to compile it told me the NullableDateTimePicker.resx file was missing."
- I extracted the code you need from : http://www.codeproject.com/cs/miscctrl/Nullable_DateTimePicker.asp
Instructions:
      1) Creat a new class on your project called DateTimePicker.
      2) Clear all code in it and copy/paste the one bellow.
      3) You can change the NameSpace if you like.


//----------------------------------------------------------------------------------
// - Author                     - Pham Minh Tri
// - Last Updated      - 19/Nov/2003
//----------------------------------------------------------------------------------
// - Component:        - Nullable DateTimePicker
// - Version:          - 1.0
// - Description:      - A datetimepicker that allow null value.
//----------------------------------------------------------------------------------

using System;
using System.Windows.Forms;  

namespace UIComponent
{
      /// <summary>
      /// Summary description for DateTimePicker.
      /// </summary>
      public class DateTimePicker : System.Windows.Forms.DateTimePicker  
      {
            private DateTimePickerFormat oldFormat = DateTimePickerFormat.Long;
            private string oldCustomFormat = null;
            private bool bIsNull = false;

            public DateTimePicker() : base()
            {
            }

            public new DateTime Value
            {
                  get
                  {
                        if (bIsNull)
                              return DateTime.MinValue;
                        else
                              return base.Value;
                  }
                  set
                  {
                        if (value == DateTime.MinValue)
                        {
                              if (bIsNull == false)
                              {
                                    oldFormat = this.Format;
                                    oldCustomFormat = this.CustomFormat;
                                    bIsNull = true;
                              }

                              this.Format = DateTimePickerFormat.Custom;
                              this.CustomFormat = " ";
                        }
                        else
                        {
                              if (bIsNull)
                              {
                                    this.Format = oldFormat;
                                    this.CustomFormat = oldCustomFormat;
                                    bIsNull = false;
                              }
                              base.Value = value;
                        }
                  }
            }

            protected override void OnCloseUp(EventArgs eventargs)
            {
                  if (Control.MouseButtons == MouseButtons.None)
                  {
                        if (bIsNull)
                        {
                              this.Format = oldFormat;
                              this.CustomFormat = oldCustomFormat;
                              bIsNull = false;
                        }
                  }
                  base.OnCloseUp (eventargs);
            }

            protected override void OnKeyDown(KeyEventArgs e)
            {
                  base.OnKeyDown (e);

                  if (e.KeyCode == Keys.Delete)
                        this.Value = DateTime.MinValue;
            }
      }
}
0
 
FrancineTaylorAuthor Commented:
Thanks for all the help, btw, Alex,

Okay, I grabbed this code, put it into a class, did a simple test just using the control and it looks like it works great for allowing you to clear a date control.

However, I added databinding to the form, binding the control to a date type column, and I ended up with exactly the same problem I had with a simple DateTimePicker.  The control chokes when the data in the dataset has a value of <null>.

When I tried adding code in the "set" method to check for a value of null, I got an error.  A value of "null" simply cannot be passed in to the control.  The base value property won't support it.

How do I get this control to work with databinding in the cases where the value is null, assuming that I want the value to continue to stay null when the changes are sent back to the database?
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
Maybe a split is in order here...

Alex :p
0
 
FrancineTaylorAuthor Commented:
I decided to split the points (sorry it took me so long to resolve this) the way I did because the Format / Parse technique was necessary even with the custom datetimepicker.   The custom dtpicker was nice, though it had to be modified further before it would work.  You can't set the datetimepicker to DateTime.MinValue, because the minimum date the control will accept is 1/1/1753.

This is the codebehind for the custom control after I got done with it:

public class myDateTimePicker : System.Windows.Forms.DateTimePicker  
{
      private bool bIsNull = false;

      // this is the minimum value that a standard date control will take
      public static DateTime nullvalue = System.DateTime.Parse("01/01/1753");
      private DateTimePickerFormat format;

      public myDateTimePicker() : base()
      {
            this.format = base.Format;
      }

      public new DateTime Value
      {
            get
            {
                  if (bIsNull)
                        return nullvalue;
                  else
                        return base.Value;
            }
            set
            {
                  if (value == DateTime.MinValue || value == nullvalue)
                  {
                        if (this.bIsNull == false)
                        {
                              //oldCustomFormat = this.CustomFormat;
                              this.bIsNull = true;
                        }

                        this.Format = DateTimePickerFormat.Custom;
                        this.CustomFormat = " ";
                  }
                  else
                  {
                        if (bIsNull)
                        {
                              this.Format = this.format;
                              this.bIsNull = false;
                        }
                        base.Value = value;
                  }
            }
      }
      public void SetToNull()
      {
            if (!bIsNull)
            {
                  this.Value = nullvalue;
            }
      }
      public Boolean IsNull()
      {
            return this.bIsNull;
      }
      public void SetFormat(DateTimePickerFormat pf)
      {
            this.format = pf;
            if (!this.bIsNull)
                  this.Format = pf;
      }
      protected override void OnCloseUp(EventArgs eventargs)
      {
            if (Control.MouseButtons == MouseButtons.None)
            {
                  if (this.bIsNull)
                  {
                        this.Format = this.format;
                        this.bIsNull = false;
                  }
            }
            base.OnCloseUp (eventargs);
      }

      protected override void OnKeyDown(KeyEventArgs e)
      {
            base.OnKeyDown (e);

            if (e.KeyCode == Keys.Delete)
                  this.Value = nullvalue;
      }
}  // class myDateTimePicker



Here is how I ended up implementing it:

// here is the module level declaration of the custom control
private myDateTimePicker dtFired;

// this goes in the form load
CreateDateBinding("employee.fired", dtFired);

// and here are the methods that go with the databinding
private void FormatDateBinding(object sender, ConvertEventArgs cevent)
{
      if (cevent.DesiredType != typeof(DateTime))
      {
            cevent.Value =  myDateTimePicker.nullvalue;
      }
      else if (cevent.Value == System.DBNull.Value)
      {
            cevent.Value = myDateTimePicker.nullvalue;
      }
}
private void ParseDateBinding(object sender, ConvertEventArgs cevent)
{
      if ((DateTime) cevent.Value == myDateTimePicker.nullvalue)
            cevent.Value = System.DBNull.Value;
}
private void CreateDateBinding(String psColumn, myDateTimePicker pdt)
{
      Binding bn = new Binding("Value", dsEmployee, psColumn);
      bn.Format += new ConvertEventHandler(this.FormatDateBinding);
      bn.Parse += new ConvertEventHandler(this.ParseDateBinding);
      pdt.DataBindings.Add(bn);
}

Thanks to both sumix and AlexCode for the solution!
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 7
  • 5
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now