Tuesday, September 18, 2012

Setting the Value for a SharePoint DateTimeField not working?

Some day's I stand amazed by the simplicity and rich features the SharePoint API gives to the developer.  But some days (they seem to pop up more and more these days), I can only shake my head at the pure stupidity it seems from the Microsoft SharePoint team.

Problem:

Take the DateTimeField.  I'm busy rending controls (from a list) in order to build a custom edit form.  Everything seems to render perfectly, including the DateTimeField. Normally you'd do something like this :
private void CreateControl(SPList list, string internalName, object val)
{
 SPField field = list.Fields.GetField(internalName);
 if (field == null)
  return;
 
 BaseFieldControl fieldRenderingControl = field.FieldRenderingControl;
 fieldRenderingControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");
 fieldRenderingControl.ControlMode = SPControlMode.New;
 fieldRenderingControl.ListId = list.ID;
 fieldRenderingControl.FieldName = field.InternalName;
 fieldRenderingControl.RenderContext = SPContext.GetContext(HttpContext.Current, list.DefaultView.ID, list.ID, adapter.Web);
 
 // Per example only.  Set the Value, cast to type if necessary.
 fieldRenderingControl.Value = val;
 
 this.Controls.Add(fieldRenderingControl);
}
This renders basic controls (excluding the Taxonomy and Custom FieldType controls) in a fairly straight forward and easy way. The problem comes in when you try and set the Value of a DateTimeField control. You'll end up with "an Object reference not set" error. I haven't had the time to fire up Reflector, so I'm not exactly sure what's happening here.

Solution :

I've ended up creating a DateTimeControl, whenever the DateTimeField pops up. My code ended up looking something like this:
private void CreateControl(SPList list, string internalName, object val)
{
 SPField field = list.Fields.GetField(internalName);
 if (field == null)
  return;

 if (field.FieldRenderingControl.GetType().Equals(typeof(DateTimeField)))
 {
  DateTimeControl dateTimeControl = new DateTimeControl();

  SPFieldDateTime sp = (SPFieldDateTime)field;
  if (sp.DisplayFormat == SPDateTimeFieldFormatType.DateOnly)
  {
   dateTimeControl.DateOnly = true;
  }
  dateTimeControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");

  // Set the value
  dateTimeControl.SelectedDate = (DateTime)val;

  this.Controls.Add(dateTimeControl);
 }
 else
 {
  BaseFieldControl fieldRenderingControl = field.FieldRenderingControl;
  fieldRenderingControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");
  fieldRenderingControl.ControlMode = SPControlMode.New;
  fieldRenderingControl.ListId = list.ID;
  fieldRenderingControl.FieldName = field.InternalName;
  fieldRenderingControl.RenderContext = SPContext.GetContext(HttpContext.Current, list.DefaultView.ID, list.ID, adapter.Web);

  // Per example only.  Set the Value, cast to type if necessary.
  fieldRenderingControl.Value = val;
  
  this.Controls.Add(fieldRenderingControl);
 }
}
Not the perfect solution, but it works. In my next post I'll reveal the entire control that will render the Taxonomy controls as well. Happy programming!

Important and Useful Links: