views:

26

answers:

2

I have a user control with a WebDateTimeEdit server control on it (essentially a TextBox). I'd like to be able to set some of the server control's properties by way of the user control's markup or programatically. for example I have this defined on my user control:

public string CssClass
{
    get { return this.WebDateTimeEdit1.CssClass; }
    set { this.WebDateTimeEdit1.CssClass = value; }
}

which allows me to do

<uc1:MyControl ID="MyControl1" runat="server" CssClass="fancycss"  />

and this works. but if I want to add a control through code,

MyControl myControl2 = new MyControl();
MyControl.CssClass = "fancycss";

this blows up because WebDateTimeEdit1 is null.

is there any way I can make this happen? also can do I do this

myControl2 .Font.Size = FontUnit.Point(8);

where the Font property is read only on the server control?

+1  A: 

It depends on how your control is defined (is it a CompositeControl?), But generally speaking, you want to call EnsureChildControls() as the first line of the setter (and likely the getter too)

Matt Greer
i have it as `public partial class MyControl : System.Web.UI.UserControl`. should I change it?
lincolnk
You shouldn't necessarily change it, it may be fine. But I would recommend looking into `System.Web.UI.WebControls.CompositeControl` and seeing if that works better, it's a class specifically designed for making controls that are composed of sub controls. It's a nice base class to work with.
Matt Greer
EnsureChildControls() didn't seem to work with UserControl as the base (maybe i'm doing it wrong) so i rebuilt it from a CompositeControl base. seems to work, thanks!
lincolnk
A: 

Hi,

The issue you are facing is due to the fact that web controls by nature are stateless. You need to persist the value of the properties you are setting so they are accessable between postbacks. Below is an example that implements asp.net viewstate.

So for example to enable state and avoid the null condition you are experienceing with the CssClass property of your custom control you can implement the propery as follows.

private string CssClass
{
  get
  {
    return (string)ViewState["cssclass"];
  }
  set
  {
    ViewState["cssclass"] = value;
  }
}

I have included a sample user control I wrote recently that will give you a model to work from.

    using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace Pdc.EventPro.WebControls
{
  [DefaultProperty("Text"), ToolboxData("<{0}:AnchorDomain1 runat=server></{0}:AnchorDomain1>")]
  public class AnchorDomain : Control
  {
    private string _href = string.Empty;

    public AnchorDomain()
    {
      VirtualPath = HttpContext.Current.Request.Path.Substring(0, HttpContext.Current.Request.Path.LastIndexOf("/") + 1);
    }

    private string VirtualPath
    {
      get
      {
        return (string)ViewState["virtualPath"];
      }
      set
      {
        ViewState["virtualPath"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("Performance Development Corporation")]
    public string Title
    {
      get
      {
        return (string)ViewState["title"];
      }

      set
      {
        ViewState["title"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("")]
    public string LinkText
    {
      get
      {
        return (string)ViewState["linktext"];
      }

      set
      {
        ViewState["linktext"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("")]
    public string Url
    {
      get
      {
        return (string)ViewState["url"];
      }

      set
      {
        ViewState["url"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("false")]
    public bool UsePageVirtualPath
    {
      get
      {
        return (bool)ViewState["useVirtualPath"];
      }

      set
      {
        ViewState["useVirtualPath"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("false")]
    public string CssClass
    {
      get
      {
        return (string)ViewState["CssClass"];
      }

      set
      {
        ViewState["CssClass"] = value;
      }
    }

    protected override void Render(HtmlTextWriter writer)
    {
      if (string.IsNullOrEmpty(Url) && UsePageVirtualPath == false)
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), HttpContext.Current.Request.ApplicationPath).ToString();
      }
      else if (!string.IsNullOrEmpty(Url) && UsePageVirtualPath == true)
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), CombineUri(VirtualPath, Url)).ToString();
      }
      else
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), CombineUri(HttpContext.Current.Request.ApplicationPath, Url)).ToString();
      }

      writer.WriteBeginTag("a");
      writer.WriteAttribute("href", _href);
      writer.WriteAttribute("title", Title);
      writer.WriteAttribute("class", CssClass);
      writer.Write(HtmlTextWriter.TagRightChar);
      writer.Write(LinkText);
      writer.WriteEndTag("a");

      base.Render(writer);
    }

    private Uri CreateUri(string baseUri, string relativeUri)
    {
      Uri result = null;

      if (Uri.TryCreate(new Uri(baseUri), relativeUri, out result))
      {
        return result;
      }

      return result;
    }

    private string CombineUri(string basePath1, string basePath2)
    {
      return string.Format("{0}/{1}", basePath1.TrimEnd('/'), basePath2.TrimStart('/')); 
    }
  }
}

Enjoy!

Doug
He doesn't want to persist the CssClass in the parent control's ViewState but rather push it down into a child control. The child control should store the CssClass in its ViewState.
Matt Greer