Forum Moderators: open

Message Too Old, No Replies

Accessing Viewstate of embedded user control

user control inside a datalist

         

mattglet

10:17 pm on Oct 5, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Code on default.aspx:
<asp:datalist id = "DL1" runat = "server">
<itemtemplate>
<My:Control id = "MyControl" runat = "server">
</itemtemplate>
</asp:datalist>

Background:
MyControl is a 1 week view of an event calendar. It has "<" and ">" linkbuttons to view upcoming/previous weeks. There are onclick handlers attached to these linkbuttons. Upon first page load, each instance of MyControl checks the viewstate to see if a "show date" is present. If not, it defaults to today's date, and store's today's date into viewstate. When you click the linkbuttons, a postback is performed, and the page checks viewstate again for a date. If a date is there, it subtracts 7 days, stores the new show date into viewstate, and populates the calendar based on the new dates.

Problem:
On postback, the viewstate set by the user control is not properly being read by default.aspx. It's like the viewstate isn't being set, but in actuality, it's just a simple ViewState("showdate") = ShowDate. (ShowDate is a property)

I'm sure this is a noob problem, and I'm willing to admit it ;)

emsaw

12:11 am on Oct 6, 2005 (gmt 0)

10+ Year Member



It's not working like you want because your usercontrol is being dynamically generated within the datalist..(i.e. no viewstate for the usercontrol because it's trashed and recreated on every roundtrip)

It's been a while since I last ran across this, but I'm pretty sure you need to set the date for each usercontrol(expose a property in the usercontrol to set) in the OnItemDataBound event of the datalist.

I'll poke around my previous projects to try to find an example.

-------
[added]


DL1_OnItemDataBound(object sender, DataGridItemEventArgs e)
{
switch( e.Item.ItemType.ToString() )
{
case "AlternatingItem":
case "Item":
UserControl ucMyControl = (UserControl)e.Item.FindControl("MyControl");
ucMyControl.DisplayDate = ViewState["showdate"];
break;
case "EditItem":
break;
}
}

[/added]

er.. something like that...

-Mark

mattglet

1:02 am on Oct 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks for the explanation Mark.

I now don't understand how I'm supposed to set the dates from within the user controls, if I can't keep track of the dates being used (because of no viewstate).

emsaw

3:28 pm on Oct 6, 2005 (gmt 0)

10+ Year Member



you could do something like this:
In your usercontrol, set a public property, say

DateTime _dispDate = DateTime.Now;
public DateTime DispDate
{
get{ return _dispDate;}
set{ _dispDate = DateTime.Parse(value);}
}

Then, in the PageLoad of your usercontrol, you'd use this property to set your date. I'm assuming it's a standard Calendar Control named eventCal .

eventCal.SelectedDate = _dispDate;
eventCal.VisibleDate = _dispDate;

..
Then in your aspx page, you'd hook up your OnItemDataBound event for the DataList, and from here you find the control and set the public property you created in your usercontrol.

DL1_OnItemDataBound(object sender, DataGridItemEventArgs e)
{
switch( e.Item.ItemType.ToString() )
{
case "AlternatingItem":
case "Item":
UserControl ucMyControl = (UserControl)e.Item.FindControl("MyControl");
ucMyControl.DispDate = ViewState["showdate"];
break;
case "EditItem":
break;
}
}

Anyway, that's how I did it IIRC.

mattglet

6:11 pm on Oct 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



My goal is to have the ability to have a separate viewstate for all the controls in the datalist. This is because I would like to be able to navigate any calendar (it's not a true calendar control, it's a custom tool I built) on the page, but let each of them have their date they are associated with. Is this even possible?

<__Oct 2005__>
____View 1____

<__Mar 2005__>
____View 2____

<__Nov 2004__>
____View 3____

This is a minor representation of what I'll have. The < & > are my nav linkbuttons.

emsaw

6:25 pm on Oct 6, 2005 (gmt 0)

10+ Year Member



mattglet,

Absolutely. You'll have to figure out how you want to store and retrieve the starting date for each unique control, but the solution I've pointed to should still be valid.

You could, say, create a sequence of viewstate vars if you have a static number of custom calendars you are displaying.. ie. ccal00_startdate, ccal01_startdate, ccal02_startdate, etc.

then in the OnItemDateBound event, depending on which DataList ordinal position you are at, you could pop the corresponding value into the exposed property of the control for the control to render the corresponding date range.

-Mark

mattglet

6:37 pm on Oct 6, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The number of controls is very dynamic. It's tough, because all my navigation is controlled by things inside the control. How do I get those values back out to the parent page to store correctly?

I guess what throws me off is this:

ucMyControl.DispDate = ViewState["showdate"];

Where do you set the viewstate to begin with?

sigh... I can't wrap my head around this one at all.

emsaw

7:21 pm on Oct 6, 2005 (gmt 0)

10+ Year Member



I just thought of a little hack that will get you what you want.. it ain't pretty, but it works This 'bad' idea may give you a 'good' idea to run with. :P

I created a test page on my localhost:

DataListCalendars.aspx
---------------------
<%@ Page language="c#" Codebehind="DataListCalendars.aspx.cs" AutoEventWireup="false" Inherits="localhost.DataListCalendars" %>
<%@ Register TagPrefix="Local" TagName="EventCalendar" Src="CustomCalendar.ascx" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>DataListCalendars</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name=vs_defaultClientScript content="JavaScript">
<meta name=vs_targetSchema content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="FlowLayout">

<form id="Form1" method="post" runat="server">
<asp:DataList id=dListCalendarContainer runat="server">
<ItemTemplate>
<Local:EventCalendar id="EventCal" runat="server" />
</ItemTemplate>
</asp:DataList>

</form>

</body>
</HTML>
---------------------

DataListCalendars.aspx.cs
---------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Collections.Specialized;

namespace localhost
{
/// <summary>
/// Summary description for DataListCalendars.
/// </summary>
public class DataListCalendars : System.Web.UI.Page
{
protected System.Web.UI.WebControls.DataList dListCalendarContainer;

private void Page_Load(object sender, System.EventArgs e)
{
if(! Page.IsPostBack )
{
ArrayList arr = new ArrayList();
arr.Add("0");
arr.Add("1");
arr.Add("2");

dListCalendarContainer.DataSource = arr;
dListCalendarContainer.DataBind();
}
}

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.dListCalendarContainer.ItemDataBound += new System.Web.UI.WebControls.DataListItemEventHandler(this.dListCalendarContainer_ItemDataBound);
this.Load += new System.EventHandler(this.Page_Load);

}
#endregion

private void dListCalendarContainer_ItemDataBound(object sender, System.Web.UI.WebControls.DataListItemEventArgs e)
{
switch( e.Item.ItemType.ToString() )
{
case "AlternatingItem":
case "Item":
break;
case "EditItem":
break;
}
}
}
}

---------------------

Then created this usercontrol with a simple calendar control in it.

CustomCalendar.ascx
---------------------
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="CustomCalendar.ascx.cs" Inherits="localhost.CustomCalendar" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<asp:Calendar id=EventCal runat="server"></asp:Calendar>
---------------------

CustomCalendar.ascx.cs
---------------------
namespace localhost
{
using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

/// <summary>
///Summary description for CustomCalendar.
/// </summary>
public class CustomCalendar : System.Web.UI.UserControl
{
protected System.Web.UI.WebControls.Calendar EventCal;

private void Page_Load(object sender, System.EventArgs e)
{
if(ViewState[this.ClientID] == null)
{
ViewState[this.ClientID] = DateTime.Today.ToString();
}
EventCal.VisibleDate = DateTime.Parse(ViewState[this.ClientID].ToString());
EventCal.SelectedDate = DateTime.Parse(ViewState[this.ClientID].ToString());
}

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
///Required method for Designer support - do not modify
///the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.EventCal.VisibleMonthChanged += new System.Web.UI.WebControls.MonthChangedEventHandler(this.EventCal_VisibleMonthChanged);
this.Load += new System.EventHandler(this.Page_Load);

}
#endregion

private void EventCal_VisibleMonthChanged(object sender, System.Web.UI.WebControls.MonthChangedEventArgs e)
{
ViewState[this.ClientID] = EventCal.VisibleDate;
}
}
}
---------------------

HTH,

mark