A bit stuck with properties in a user control

Discussion in 'ASP .Net' started by Alan Silver, Feb 21, 2005.

  1. Alan Silver

    Alan Silver Guest

    Hello,

    I'm trying to write a simple user control as an exercise (and 'cos it
    might be useful). I am trying to do a simple date picker, which consists
    of three drop down lists, one for the day, one for the month and one for
    the year. I know this isn't earth-shattering stuff, but I'm still
    learning, so please be patient!!

    I'm having trouble with the properties of the control. I have created
    the control OK and it displays fine. I added a method that sets the
    range for the year drop down, and in the Form_Load event, I check to see
    if it's been called, and if not, I use a default year range. All fine so
    far.

    Now, I wanted to add a property for the day, so that this could be set
    or got. I did the following ...

    public int Day {
    get {
    return System.Convert.ToInt32(drpDay.SelectedItem.Text);
    }
    set {
    if (Day<=0 || Day>31) {
    drpDay.SelectedIndex = 0;
    } else {
    drpDay.SelectedIndex = Day - 1;
    }
    }
    }

    where drpDay is the name of the drop down for the day.

    In the page I was using to test this, I did the following ...

    void Page_Load(Object sender, EventArgs e) {
    if (!IsPostBack) {
    dtpDate.SetYearRange(1990, 2000);
    dtpDate.Day = 3;
    }
    }

    which gave a compile error on the line dtpDate.Day = 3;, saying "Object
    reference not set to an instance of an object". I'm not sure what the
    problem is as drpDate definitely exists, and the Day property exists and
    is public.

    Anyone able to explain what I did wrong? TIA. The full code is shown
    below in case it is needed.

    Thanks,

    Alan

    DatePicker.ascx
    ============
    <script runat="server" Language="C#">

    void Page_Load(Object sender, EventArgs e) {
    if (!IsPostBack) {
    int i;
    for (i=1; i<=31; i++) {
    drpDay.Items.Add(i.ToString());
    }
    if (drpYear.Items.Count == 0) {
    SetYearRange(DateTime.Now.Year, DateTime.Now.Year+10);
    }
    }
    }

    public void SetYearRange(int StartYear, int EndYear) {
    int i;
    for (i=StartYear; i<=EndYear; i++) {
    drpYear.Items.Add(i.ToString());
    }
    }

    public int Day {
    get {
    return System.Convert.ToInt32(drpDay.SelectedItem.Text);
    }
    set {
    if (Day<=0 || Day>31) {
    drpDay.SelectedIndex = 0;
    } else {
    drpDay.SelectedIndex = Day - 1;
    }
    }
    }

    </script>

    <asp:DropDownList ID="drpDay" Runat="Server" />&nbsp;<asp:DropDownList
    ID="drpMonth" Runat="Server"><asp:ListItem Text="January"
    /><asp:ListItem Text="February" /><asp:ListItem Text="March"
    /><asp:ListItem Text="April" /><asp:ListItem Text="May" /><asp:ListItem
    Text="June" /><asp:ListItem Text="July" /><asp:ListItem Text="August"
    /><asp:ListItem Text="September" /><asp:ListItem Text="October"
    /><asp:ListItem Text="November" /><asp:ListItem Text="December"
    /></asp:DropDownList>&nbsp;<asp:DropDownList ID="drpYear" Runat="Server"
    />





    TestDatePicker.aspx
    ===============
    <%@ Page Language="C#" Debug="true" %>
    <%@ Register TagPrefix="Pixata" TagName="DatePicker"
    Src="DatePicker.ascx" %>

    <script runat="server">
    void Page_Load(Object sender, EventArgs e) {
    if (!IsPostBack) {
    dtpDate.SetYearRange(1990, 2000);
    dtpDate.Day = 3;
    }
    }
    </script>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <html>
    <head>
    <title>Test of my date picker custom control</title>
    </head>

    <body>
    <form runat="server">
    <Pixata:DatePicker ID="dtpDate" Runat="Server" />
    </form>
    </body>
    </html>




    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 21, 2005
    #1
    1. Advertising

  2. Alan Silver

    Karl Seguin Guest

    Alan,
    I know you said that it was, but I'm almost sure drpDay doesn't exist.. :)
    make sure it's declared as a protected or public field and ther isn't a
    typo...also, this seems like it could/will cause problems:

    drpDay.SelectedIndex = Day - 1;


    Day will recursively call itself...don't you mean value - 1 ?

    Karl


    --
    MY ASP.Net tutorials
    http://www.openmymind.net/


    "Alan Silver" <> wrote in message
    news:...
    > Hello,
    >
    > I'm trying to write a simple user control as an exercise (and 'cos it
    > might be useful). I am trying to do a simple date picker, which consists
    > of three drop down lists, one for the day, one for the month and one for
    > the year. I know this isn't earth-shattering stuff, but I'm still
    > learning, so please be patient!!
    >
    > I'm having trouble with the properties of the control. I have created
    > the control OK and it displays fine. I added a method that sets the
    > range for the year drop down, and in the Form_Load event, I check to see
    > if it's been called, and if not, I use a default year range. All fine so
    > far.
    >
    > Now, I wanted to add a property for the day, so that this could be set
    > or got. I did the following ...
    >
    > public int Day {
    > get {
    > return System.Convert.ToInt32(drpDay.SelectedItem.Text);
    > }
    > set {
    > if (Day<=0 || Day>31) {
    > drpDay.SelectedIndex = 0;
    > } else {
    > drpDay.SelectedIndex = Day - 1;
    > }
    > }
    > }
    >
    > where drpDay is the name of the drop down for the day.
    >
    > In the page I was using to test this, I did the following ...
    >
    > void Page_Load(Object sender, EventArgs e) {
    > if (!IsPostBack) {
    > dtpDate.SetYearRange(1990, 2000);
    > dtpDate.Day = 3;
    > }
    > }
    >
    > which gave a compile error on the line dtpDate.Day = 3;, saying "Object
    > reference not set to an instance of an object". I'm not sure what the
    > problem is as drpDate definitely exists, and the Day property exists and
    > is public.
    >
    > Anyone able to explain what I did wrong? TIA. The full code is shown
    > below in case it is needed.
    >
    > Thanks,
    >
    > Alan
    >
    > DatePicker.ascx
    > ============
    > <script runat="server" Language="C#">
    >
    > void Page_Load(Object sender, EventArgs e) {
    > if (!IsPostBack) {
    > int i;
    > for (i=1; i<=31; i++) {
    > drpDay.Items.Add(i.ToString());
    > }
    > if (drpYear.Items.Count == 0) {
    > SetYearRange(DateTime.Now.Year, DateTime.Now.Year+10);
    > }
    > }
    > }
    >
    > public void SetYearRange(int StartYear, int EndYear) {
    > int i;
    > for (i=StartYear; i<=EndYear; i++) {
    > drpYear.Items.Add(i.ToString());
    > }
    > }
    >
    > public int Day {
    > get {
    > return System.Convert.ToInt32(drpDay.SelectedItem.Text);
    > }
    > set {
    > if (Day<=0 || Day>31) {
    > drpDay.SelectedIndex = 0;
    > } else {
    > drpDay.SelectedIndex = Day - 1;
    > }
    > }
    > }
    >
    > </script>
    >
    > <asp:DropDownList ID="drpDay" Runat="Server" />&nbsp;<asp:DropDownList
    > ID="drpMonth" Runat="Server"><asp:ListItem Text="January"
    > /><asp:ListItem Text="February" /><asp:ListItem Text="March"
    > /><asp:ListItem Text="April" /><asp:ListItem Text="May" /><asp:ListItem
    > Text="June" /><asp:ListItem Text="July" /><asp:ListItem Text="August"
    > /><asp:ListItem Text="September" /><asp:ListItem Text="October"
    > /><asp:ListItem Text="November" /><asp:ListItem Text="December"
    > /></asp:DropDownList>&nbsp;<asp:DropDownList ID="drpYear" Runat="Server"
    > />
    >
    >
    >
    >
    >
    > TestDatePicker.aspx
    > ===============
    > <%@ Page Language="C#" Debug="true" %>
    > <%@ Register TagPrefix="Pixata" TagName="DatePicker"
    > Src="DatePicker.ascx" %>
    >
    > <script runat="server">
    > void Page_Load(Object sender, EventArgs e) {
    > if (!IsPostBack) {
    > dtpDate.SetYearRange(1990, 2000);
    > dtpDate.Day = 3;
    > }
    > }
    > </script>
    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    > <html>
    > <head>
    > <title>Test of my date picker custom control</title>
    > </head>
    >
    > <body>
    > <form runat="server">
    > <Pixata:DatePicker ID="dtpDate" Runat="Server" />
    > </form>
    > </body>
    > </html>
    >
    >
    >
    >
    > --
    > Alan Silver
    > (anything added below this line is nothing to do with me)
    Karl Seguin, Feb 21, 2005
    #2
    1. Advertising

  3. Alan Silver

    Alan Silver Guest

    >Hello,

    Just to answer my own question (in case it's of use to anyone), I found
    out that the properties were being set before the Page_Load event had
    fired. As I was populating the drop down for the day in that event, when
    the property was being set, the drop down was empty. Presumably the
    error I saw was because the collection of list items had not been set to
    anything.

    Sorted now.

    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 21, 2005
    #3
  4. Alan Silver

    Alan Silver Guest

    >Alan,
    >I know you said that it was, but I'm almost sure drpDay doesn't exist.. :)
    >make sure it's declared as a protected or public field and ther isn't a
    >typo


    Yup, it exists. If you look at the code I posted, it is the first of the
    three drop down lists in the user control.

    >...also, this seems like it could/will cause problems:
    >
    >drpDay.SelectedIndex = Day - 1;
    >
    >Day will recursively call itself...don't you mean value - 1 ?


    Yup, I spotted that one after posting. That sorted out one of the
    problems ;-)

    I'm still trying to work out the best way to sort out this problem of
    properties being set before the Page_Load event fires. I was wondering
    about having three private variables, one for the selected year, one for
    the start year and one for the end year. All would have initial values
    of zero. In each of the three property codes, I would check to see if
    all three of these are non-zero, and if they are, then set up the drop
    down with the range of years and set the selected year. In the Page_Load
    event, I could then check to see if the start and end years were set,
    but not the selected year. If so, I would set up the drop down, but not
    select a value.

    I haven't tried this yet, but it seems reasonably straightforward, if a
    little twisted for such a simple requirement. Is there a better way to
    do it?

    Thanks for the reply

    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 21, 2005
    #4
  5. Alan Silver

    Karl Seguin Guest

    Alan:
    As you've learnt, you typically don't access controls within properties,
    because they aren't necessarily available yet. Having private fields which
    are exposed via public properties, and then using the values in those fields
    during Page_Load is really the only/best way to go.

    There's really two ways of dealing with your situation. You can assign
    default values to the start and end year,which simplifies your code...in
    your page_load you make use of these variables and if they've been set to
    something other than the default, you really couldn't care any less. Or, if
    you must have the values set (ie, you don't want to use defaults), you
    typically check if they were set and if not throw an exception or atleast
    hide the control.. Which you use depends on your exact needs...one isn't
    better than another really..depends on how you want/need it to behave. I
    find it a little tricky dealing with default values with nulls...because is
    0 the default value or was it entered? In .net 2.0 we get nullable types
    where you can assign null to a integer...thus making it easier to figure out
    if it's a default value or if it's an actual user-entered one..

    Karl

    --
    MY ASP.Net tutorials
    http://www.openmymind.net/


    "Alan Silver" <> wrote in message
    news:p...
    > >Alan,
    > >I know you said that it was, but I'm almost sure drpDay doesn't exist..

    :)
    > >make sure it's declared as a protected or public field and ther isn't a
    > >typo

    >
    > Yup, it exists. If you look at the code I posted, it is the first of the
    > three drop down lists in the user control.
    >
    > >...also, this seems like it could/will cause problems:
    > >
    > >drpDay.SelectedIndex = Day - 1;
    > >
    > >Day will recursively call itself...don't you mean value - 1 ?

    >
    > Yup, I spotted that one after posting. That sorted out one of the
    > problems ;-)
    >
    > I'm still trying to work out the best way to sort out this problem of
    > properties being set before the Page_Load event fires. I was wondering
    > about having three private variables, one for the selected year, one for
    > the start year and one for the end year. All would have initial values
    > of zero. In each of the three property codes, I would check to see if
    > all three of these are non-zero, and if they are, then set up the drop
    > down with the range of years and set the selected year. In the Page_Load
    > event, I could then check to see if the start and end years were set,
    > but not the selected year. If so, I would set up the drop down, but not
    > select a value.
    >
    > I haven't tried this yet, but it seems reasonably straightforward, if a
    > little twisted for such a simple requirement. Is there a better way to
    > do it?
    >
    > Thanks for the reply
    >
    > --
    > Alan Silver
    > (anything added below this line is nothing to do with me)
    Karl Seguin, Feb 22, 2005
    #5
  6. Alan Silver

    Alan Silver Guest

    >As you've learnt, you typically don't access controls within properties,
    >because they aren't necessarily available yet. Having private fields which
    >are exposed via public properties, and then using the values in those fields
    >during Page_Load is really the only/best way to go.


    Yup, spotted that one!!

    >There's really two ways of dealing with your situation. You can assign
    >default values to the start and end year,which simplifies your code...in
    >your page_load you make use of these variables and if they've been set to
    >something other than the default, you really couldn't care any less.

    <snip>

    That is a very sensible approach, and far better than the convoluted
    method I was contemplating. It's so simple, I could kick myself for not
    thinking of it[1]. I already have code in there to set default values,
    so that's not a problem. I assumed that user controls would probably
    always want these as you can never be sure if the user gave values for
    every property. Apart from certain vital ones (like ID), I was assuming
    defaults for everything.

    Thanks for the reply, I think this should be a lot easier now.

    Alan

    P.S. If you have any ideas about binding to a check box control, please
    could you look at the thread "How do I do data binding with a checkbox?"
    which I posted yesterday, but unfortunately hasn't sparked anyone's
    imagination yet ;-) I'm still stuck on that one.

    [1] In the interests of honesty, I should point out that I am not in the
    habit of kicking myself, even when it is highly deserved. I used the
    expression as an example of the rich and idiomatic language we have ;-)

    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 22, 2005
    #6
  7. Alan Silver

    Alan Silver Guest

    >There's really two ways of dealing with your situation. You can assign
    >default values to the start and end year,which simplifies your code...in
    >your page_load you make use of these variables and if they've been set
    >to something other than the default, you really couldn't care any less.


    OK, I just thought of something whilst trying this out.

    As I see it, properties are likely to be set in two places, either when
    the control is specified, eg ...

    <Me:MyControl ID="Fred" Year="2005" />

    or at some point in the code.

    My problem is that I'm not sure if your approach would handle both.
    Suppose the public property for the year just set the private member
    variable, and the Page_Load event for the control actually set the drop
    down, then this would be fine for when the control first loads, but
    wouldn't do anything if the property were changed later.

    How do I handle this? I thought of having a private Boolean member
    variable, m_Loaded, that is initially false, but set to true in the
    Page_Load event to indicate that the control has loaded. The public
    property would then do something like ...

    m_Year = value; // save the value in the private member variable
    if (m_Loaded) {
    dropYear.SelectedItem = m_Year; // set the drop down
    }

    I think this would work, but it seems a little inelegant. I'm sure there
    is a better way of doing it. Any thoughts? TIA

    P.S. I know the code shown above won't actually set a drop down
    correctly as it assumes that "value" contains a number that relates to
    the index of the drop down's Item collection. I just used that code for
    simplicity. I currently go through each item in the drop down looking to
    see if the text matches. Again, this works, but seems inelegant. If you
    know of a better way to set a drop down, given the Text value of one of
    the items, please let me know. Thanks.

    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 22, 2005
    #7
  8. Alan Silver

    Karl Seguin Guest

    Alan:
    You are correct, but I think you're worrying for nothing. It's true that if
    you change the value after the control has run through it's logic than the
    change won't automatically be reflected. But this typically won't
    happen...you'll normally set the values in the Page_Load event of the page
    and thus everything will time up nicely.

    I appreciate that you are trying to learn and it's useful to look at all
    scenarios, but do keep in mind that the simplest method will work most of
    the time. An alternative solution coul be to:

    (A) place the user control's ogic in the PreRender event...if anything
    happens after this ur screwed anyways 'cuz it's already been rendered
    (B) Use a function in the user control to handle the logic and call the
    function from the page..so instead of passing variable you explicitely have
    control over when it's done. RenderDates(startYear, EndYear, SelectedYear).
    So long as you cal the function before/during PreRender all should be fine.

    Karl

    --
    MY ASP.Net tutorials
    http://www.openmymind.net/


    "Alan Silver" <> wrote in message
    news:...
    > >There's really two ways of dealing with your situation. You can assign
    > >default values to the start and end year,which simplifies your code...in
    > >your page_load you make use of these variables and if they've been set
    > >to something other than the default, you really couldn't care any less.

    >
    > OK, I just thought of something whilst trying this out.
    >
    > As I see it, properties are likely to be set in two places, either when
    > the control is specified, eg ...
    >
    > <Me:MyControl ID="Fred" Year="2005" />
    >
    > or at some point in the code.
    >
    > My problem is that I'm not sure if your approach would handle both.
    > Suppose the public property for the year just set the private member
    > variable, and the Page_Load event for the control actually set the drop
    > down, then this would be fine for when the control first loads, but
    > wouldn't do anything if the property were changed later.
    >
    > How do I handle this? I thought of having a private Boolean member
    > variable, m_Loaded, that is initially false, but set to true in the
    > Page_Load event to indicate that the control has loaded. The public
    > property would then do something like ...
    >
    > m_Year = value; // save the value in the private member variable
    > if (m_Loaded) {
    > dropYear.SelectedItem = m_Year; // set the drop down
    > }
    >
    > I think this would work, but it seems a little inelegant. I'm sure there
    > is a better way of doing it. Any thoughts? TIA
    >
    > P.S. I know the code shown above won't actually set a drop down
    > correctly as it assumes that "value" contains a number that relates to
    > the index of the drop down's Item collection. I just used that code for
    > simplicity. I currently go through each item in the drop down looking to
    > see if the text matches. Again, this works, but seems inelegant. If you
    > know of a better way to set a drop down, given the Text value of one of
    > the items, please let me know. Thanks.
    >
    > --
    > Alan Silver
    > (anything added below this line is nothing to do with me)
    Karl Seguin, Feb 22, 2005
    #8
  9. Alan Silver

    Alan Silver Guest

    >Alan:
    >You are correct, but I think you're worrying for nothing. It's true that if
    >you change the value after the control has run through it's logic than the
    >change won't automatically be reflected. But this typically won't
    >happen...you'll normally set the values in the Page_Load event of the page
    >and thus everything will time up nicely.


    Good point, I hadn't thought of that.

    Thanks for the reply

    --
    Alan Silver
    (anything added below this line is nothing to do with me)
    Alan Silver, Feb 22, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    1,752
    Timothy Bendfelt
    Jan 19, 2007
  2. Max2006
    Replies:
    2
    Views:
    514
    Max2006
    Jul 13, 2007
  3. Replies:
    9
    Views:
    970
    Juha Nieminen
    Aug 22, 2007
  4. Ryan
    Replies:
    0
    Views:
    105
  5. Jeff.M
    Replies:
    6
    Views:
    172
    Lasse Reichstein Nielsen
    May 4, 2009
Loading...

Share This Page