Answered by:
Custom Control - CompositeControl - Problem !

Question
-
User131956424 posted
Hello everyone,
I'm writing a custom control [ 2 dropdowns / calendar / textbox / button ]
the 1st time the control runs its running fine, but on calendar_selectionChanged I cant get the text from the textbox
the following is my code :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;
using
System;using
System.ComponentModel;using
System.Drawing;using
System.Security.Permissions;using
System.Web;using
System.Web.UI;using
System.Web.UI.WebControls; namespace AMASSDatePicker{
[
AspNetHostingPermission(SecurityAction.Demand,Level =
AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand,Level =
AspNetHostingPermissionLevel.Minimal), DefaultEvent("Submit"), DefaultProperty("ButtonText"), ToolboxData("<{0}:AMASSDatePicker runat=\"server\"> </{0}:AMASSDatePicker>"),]
public class AMASSDatePicker : CompositeControl{
private DropDownList months = new DropDownList(); private DropDownList years = new DropDownList(); private Calendar calendar = new Calendar(); private TextBox txtDate = new TextBox(); private ImageButton btnDate; // The following properties are delegated to // child controls.[
Bindable(true),Category("Appearance")]
public Calendar Calendar{
get{
EnsureChildControls();
return calendar;}
set{
EnsureChildControls();
calendar = value;}
}
[
Bindable(true), Category("Appearance"), DefaultValue("")]
public String Text{
get{
EnsureChildControls();
return txtDate.Text;}
set{
EnsureChildControls();
txtDate.Text = value;}
}
protected override void RecreateChildControls(){
EnsureChildControls();
}
protected override void CreateChildControls(){
this.Controls.Clear();txtDate.Enabled =
false; btnDate = new ImageButton();String imageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "AMASSDatePicker.Resources.Calendar.gif");btnDate.ImageUrl = imageUrl;
btnDate.Click +=
new ImageClickEventHandler(btnDate_Click); this.Controls.Add(btnDate);calendar.SelectionChanged +=
new EventHandler(calendar_SelectionChanged); this.Controls.Add(calendar);months.SelectedIndexChanged +=
new EventHandler(DropDowns_SelectedIndexChanged); this.Controls.Add(months);years.SelectedIndexChanged +=
new EventHandler(DropDowns_SelectedIndexChanged); this.Controls.Add(years);if (!Page.IsPostBack){
months.AutoPostBack =
true; years.AutoPostBack = true; //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ months.Visible = false;years.Visible =
false; calendar.Visible = false; //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ txtDate.Enabled = false;txtDate.EnableViewState =
true; txtDate.Text = DateTime.Now.ToString("dd/MMM/yyyy");txtDate.Width =
Unit.Pixel(90); calendar.NextMonthText = "";calendar.PrevMonthText =
""; calendar.SelectedDate = Convert.ToDateTime(DateTime.Now.ToString("dd/MMM/yyyy"));calendar.TodaysDate = calendar.SelectedDate;
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ years.Width = Unit.Percentage(49);for (int year = DateTime.Now.Year - 100; year < DateTime.Now.Year + 100; year++){
years.Items.Add(year.ToString());
}
//years.Items.FindByValue(DateTime.Now.Year.ToString()).Selected = true; //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@{
switch (i){
case 1: li = new ListItem("January", i.ToString());months.Items.Add(li);
break; case 2: li = new ListItem("February", i.ToString());months.Items.Add(li);
break; case 3: li = new ListItem("March", i.ToString());months.Items.Add(li);
break; case 4: li = new ListItem("April", i.ToString());months.Items.Add(li);
break; case 5: li = new ListItem("May", i.ToString());months.Items.Add(li);
break; case 6: li = new ListItem("June", i.ToString());months.Items.Add(li);
break; case 7: li = new ListItem("July", i.ToString());months.Items.Add(li);
break; case 8: li = new ListItem("August", i.ToString());months.Items.Add(li);
break; case 9: li = new ListItem("September", i.ToString());months.Items.Add(li);
break; case 10: li = new ListItem("October", i.ToString());months.Items.Add(li);
break; case 11: li = new ListItem("November", i.ToString());months.Items.Add(li);
break; case 12: li = new ListItem("December", i.ToString());months.Items.Add(li);
break;}
i++;
}
//months.Items.FindByValue(DateTime.Now.Month.ToString()).Selected = true; //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@}
}
protected override void Render(HtmlTextWriter writer){
EnsureChildControls();
AddAttributesToRender(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Table);writer.AddAttribute(
HtmlTextWriterAttribute.Width, "600px"); writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(
HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2", false);txtDate.RenderControl(writer);
btnDate.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(HtmlTextWriterTag.Td);months.RenderControl(writer);
years.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(
HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2", false);calendar.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
// Handles the Click event of the Button and raises // the Submit event. protected virtual void DropDowns_SelectedIndexChanged(object sender, EventArgs e){
calendar.SelectedDate = Convert.ToDateTime(months.SelectedItem.Value + "/1/" + years.SelectedItem.Value);txtDate.Text = calendar.SelectedDate.ToString("dd/MMM/yyyy");calendar.TodaysDate = calendar.SelectedDate;
}
protected virtual void calendar_SelectionChanged(object sender, EventArgs e){
months.SelectedIndex = -1;
years.SelectedIndex = -1;
calendar.TodaysDate = calendar.SelectedDate;
txtDate.Text = calendar.SelectedDate.ToString("dd/MMM/yyyy");years.Items.FindByValue(calendar.SelectedDate.Year.ToString()).Selected =
true; months.Items.FindByValue(calendar.SelectedDate.Month.ToString()).Selected = true;btnDate.Visible =
true; calendar.Visible = false;months.Visible =
false; years.Visible = false;}
protected virtual void btnDate_Click(object sender, EventArgs e){
btnDate.Visible = false;months.Visible =
true; years.Visible = true;calendar.Visible = true;}
}
}
Thanks in advance.
Wednesday, June 18, 2008 4:35 PM
Answers
-
User-16411453 posted
Looks much beter now, your close, just need to tighten it up more. Fix your Properies. I like placing properties at the bottom of the page under all the subs and functions.
The Property statement below is all Wrong. Go back to a default Text Property and leave it alone.
Bindable(true), Category("Appearance"), DefaultValue("")]
public String Text { get{EnsureChildControls(); //Strip these out of your properties for proper functon ' This is for other purposes and not here
return txtDate.Text;}
set{EnsureChildControls();
txtDate.Text = value;}
}
To Render, all you need is this which is the simple way to do it. You can render the way you have it, but that is beyond my knowledge, and I see no practical purpose for it at the moment. The Atrribute tags in your RenderFunction, move them to your init function where you created the control, and keep them in groups.
protected override void Render(HtmlTextWriter writer)
{RenderContents(writer)
}
'OnInit Example, I made a table, added a tablerow, added a cell, and placed the textbox inside the cell.
'Make a Table Tag
table = New Table();
table.Width = 100
table.CellSpacing = 0;
table.CellPadding=0;
table.Style.Add(HtmlTextWriterStyle.Width, "100px");
table.Attribute.Add("border", "0");
controls.Add(table);
tr = New TableRow();
table.controls.add(tr)
td = New TableCell();
td.Style.Add(HtmlTextWriterStyle.TextAlign, "left")
td.Style.Add(HtmlTextWriterStyle.PaddingLeft, "5px");
tr.controls.Add(td)
txtDate = new TextBox(); txtDate.Enabled = false; txtDate.Text = [Text]; 'In vb, this is how you call the Property Value Text. [Text], [Width], [BorderColor], not sure how in CS, but it should be closetxtDate.Width = 90;
txtDate.Style.Add(HtmlTextWriterStyle.Width, "90px") td.Controls.Add(txtDate);- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Monday, June 23, 2008 1:10 PM
All replies
-
User-16411453 posted
protected override void CreateChildControls
change to
protected override void OnInit
Wednesday, June 18, 2008 7:43 PM -
User131956424 posted
Sorry but this didnt work.
Wednesday, June 18, 2008 11:22 PM -
User-16411453 posted
It works, but your server control structure had other issues to keep it from working. Thought you would figure it out yourself. I don't write code for folks, so this is just a cut and paste of what you posted. It is not accurate, just a reference to use.
protected override void Render(HtmlTextWriter writer) { //This Renders the contents of the control to the page RenderContents(writer) }
protected override void OnInit(EventArgs e) {
//This designs and paints the controls for use this.Controls.Clear();
String imageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "AMASSDatePicker.Resources.Calendar.gif");
txtDate = newTextBox(); txtDate.Enabled = false;
txtDate.Enabled = false; txtDate.EnableViewState = true;
txtDate.Text = DateTime.Now.ToString("dd/MMM/yyyy"); txtDate.Width = Unit.Pixel(90);
thisl.Controls.Add(txtDate); btnDate = new ImageButton();
btnDate.ImageUrl = imageUrl; btnDate.Click += new ImageClickEventHandler(btnDate_Click); this.Controls.Add(btnDate);
calandar = new Calander();
calendar.SelectionChanged += new EventHandler(calendar_SelectionChanged);
calendar.Visible = false;
calendar.NextMonthText = ""; calendar.PrevMonthText = ""; calendar.SelectedDate = Convert.ToDateTime(DateTime.Now.ToString("dd/MMM/yyyy")); calendar.TodaysDate = calendar.SelectedDate; this.Controls.Add(calendar);
months = New Months()
months.SelectedIndexChanged += new EventHandler(DropDowns_SelectedIndexChanged);
months.AutoPostBack = true;
months.Visible = false;
this.Controls.Add(months);
years.SelectedIndexChanged += new EventHandler(DropDowns_SelectedIndexChanged);
years.AutoPostBack = true;
years.Visible = false;
this.Controls.Add(years);
}
protected override void OnLoad(EventArgs e) {
//This is just like the page load in code behind, this is where you do your stuff years.Width = Unit.Percentage(49);for (int year = DateTime.Now.Year - 100; year < DateTime.Now.Year + 100; year++) years.Items.Add(year.ToString()); years.Items.FindByValue(DateTime.Now.Year.ToString()).Selected = true; months.Width = Unit.Percentage(49); int i = 1; }
Thursday, June 19, 2008 2:11 PM -
User131956424 posted
Hey jkirkerx,
Thanks alot for your support.
I'm still facing the same problem. If I used the control in a test page like the following it wont work fine.
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
protected void Page_Load(object sender, EventArgs e) { String str = AMASSDatePicker1.Text; if (Convert.ToDateTime(str) <= DateTime.Now) { Response.Write("Today + Days Be4");}
else { Response.Write("2morrow + Days After");}
}
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
The problem is that in the control, its going to the getter first before going to the calendar_SelectionChange event [ where I'm setting the value to the selectedDate ].
- To get the right value for .Text I have to click the button again.
Any idea ?!
Friday, June 20, 2008 2:31 AM -
User1968518401 posted
Try using Page Prerender event instead Page_load event in test page.
Friday, June 20, 2008 9:38 AM -
User-16411453 posted
I was just trying to give you a quick cut and paste example of how to change your server control project so that it functions without error. The example is not accurate, just a picture of how it should look. Below is OnLoad. It's like the PageLoad in code behind, but it resides inside your server control project, and not on a code behind page.
Modify your control code to the example, and make sure it renders correctly on page load. Then you can go back and add event handlers to your buttons, so that the values change correctly.
protected void OnLoad(object sender, EventArgs e) { String str = AMASSDatePicker1.Text; if (Convert.ToDateTime(str) <= DateTime.Now) {
txtDate.Text = "Today + Days Be4"; } else { txtDate.Text = "2morrow + Days After"; } }
Friday, June 20, 2008 1:36 PM -
User131956424 posted
jkirkerx, I've changed the code the way you mentioned. it looks like :
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
using
System;using
System.Collections.Generic;using
System.Text;using
System.Web.UI.WebControls;using
System.Web.UI;using
System.Web;using
System.ComponentModel;using
System.Security.Permissions; namespace AMASSDatePicker{
[
AspNetHostingPermission(SecurityAction.Demand,Level =
AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand,Level =
AspNetHostingPermissionLevel.Minimal), ToolboxData("<{0}:AMASSDatePicker runat=\"server\"> </{0}:AMASSDatePicker>"),]
public class AMASSDatePicker : CompositeControl, INamingContainer{
private DropDownList months; private DropDownList years; private Calendar calendar; private TextBox txtDate; private ImageButton btnDate;[
Bindable(true),Category("Appearance")]
public Calendar Calendar{
get{
EnsureChildControls();
return calendar;}
set{
EnsureChildControls();
calendar = value;}
}
[
Bindable(true), Category("Appearance"), DefaultValue("")]
public String Text{
get{
EnsureChildControls();
return txtDate.Text;}
set{
EnsureChildControls();
txtDate.Text = value;}
}
protected override void OnInit(EventArgs e){
this.Controls.Clear(); String imageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "AMASSDatePicker.Resources.Calendar.gif"); txtDate = new TextBox();txtDate.Enabled =
false; txtDate.Enabled = false;txtDate.Text =
DateTime.Now.ToString("dd/MMM/yyyy"); txtDate.Width = Unit.Pixel(90); this.Controls.Add(txtDate); btnDate = new ImageButton();btnDate.ImageUrl = imageUrl;
btnDate.Click += new ImageClickEventHandler(btnDate_Click); this.Controls.Add(btnDate); calendar = new Calendar();calendar.SelectionChanged +=
new EventHandler(calendar_SelectionChanged); calendar.Visible = false; calendar.NextMonthText = "";calendar.PrevMonthText =
""; calendar.SelectedDate = Convert.ToDateTime(DateTime.Now.ToString("dd/MMM/yyyy"));calendar.TodaysDate = calendar.SelectedDate;
this.Controls.Add(calendar);months =
new DropDownList(); months.SelectedIndexChanged += new EventHandler(_SelectedIndexChanged);months.AutoPostBack =
true; months.Visible = false; this.Controls.Add(months); years = new DropDownList();years.SelectedIndexChanged +=
new EventHandler(_SelectedIndexChanged); years.AutoPostBack = true;years.Visible =
false; this.Controls.Add(years);}
void _SelectedIndexChanged(object sender, EventArgs e){
calendar.SelectedDate = Convert.ToDateTime(months.SelectedItem.Value + "/1/" + years.SelectedItem.Value);txtDate.Text = calendar.SelectedDate.ToString("dd/MMM/yyyy");calendar.TodaysDate = calendar.SelectedDate;
}
void calendar_SelectionChanged(object sender, EventArgs e){
months.SelectedIndex = -1;
years.SelectedIndex = -1;
calendar.TodaysDate = calendar.SelectedDate;
Text = calendar.SelectedDate.ToString("dd/MMM/yyyy");txtDate.Text = Text;
years.Items.FindByValue(calendar.SelectedDate.Year.ToString()).Selected = true;months.Items.FindByValue(calendar.SelectedDate.Month.ToString()).Selected =
true; btnDate.Visible = true;calendar.Visible =
false; months.Visible = false;years.Visible = false;}
void btnDate_Click(object sender, ImageClickEventArgs e){
btnDate.Visible =
false; months.Visible = true;years.Visible =
true; calendar.Visible = true;}
protected override void OnLoad(EventArgs e){
//This is just like the page load in code behind, this is where you do your stuff for (int year = DateTime.Now.Year - 100; year < DateTime.Now.Year + 100; year++){
years.Items.Add(year.ToString());
}
int i = 1; ListItem li; while (i <= 12){
switch (i){
case 1:li = new ListItem("January", i.ToString());months.Items.Add(li);
break; case 2:li = new ListItem("February", i.ToString());months.Items.Add(li);
break; case 3:li = new ListItem("March", i.ToString());months.Items.Add(li);
break; case 4:li = new ListItem("April", i.ToString());months.Items.Add(li);
break; case 5:li = new ListItem("May", i.ToString());months.Items.Add(li);
break; case 6:li = new ListItem("June", i.ToString());months.Items.Add(li);
break; case 7:li = new ListItem("July", i.ToString());months.Items.Add(li);
break; case 8:li = new ListItem("August", i.ToString());months.Items.Add(li);
break; case 9:li = new ListItem("September", i.ToString());months.Items.Add(li);
break; case 10:li = new ListItem("October", i.ToString());months.Items.Add(li);
break; case 11:li = new ListItem("November", i.ToString());months.Items.Add(li);
break; case 12:li = new ListItem("December", i.ToString());months.Items.Add(li);
break;}
i++;
}
}
protected override void Render(HtmlTextWriter writer){
//This Renders the contents of the control to the pageEnsureChildControls();
AddAttributesToRender(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Table);writer.AddAttribute(
HtmlTextWriterAttribute.Width, "600px"); writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(
HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2", false);txtDate.RenderControl(writer);
btnDate.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(HtmlTextWriterTag.Td);months.RenderControl(writer);
years.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);writer.RenderBeginTag(
HtmlTextWriterTag.Td); writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2", false);calendar.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
}
}
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
and the previously mentioned example is in a web project that use this custom control @PageLoad Event.is there any idea why its keeping the old value until the next button click ?
Friday, June 20, 2008 6:22 PM -
User1968518401 posted
I had same problem in past, It is because ur page.aspx's page_load fires first then it fires ur cc's action events then it fires page.aspx's page_prerender,
try using page_prerender method of page.aspx instead page_load. if you not sure post ur aspx.cs code.
Monday, June 23, 2008 8:47 AM -
User-16411453 posted
Looks much beter now, your close, just need to tighten it up more. Fix your Properies. I like placing properties at the bottom of the page under all the subs and functions.
The Property statement below is all Wrong. Go back to a default Text Property and leave it alone.
Bindable(true), Category("Appearance"), DefaultValue("")]
public String Text { get{EnsureChildControls(); //Strip these out of your properties for proper functon ' This is for other purposes and not here
return txtDate.Text;}
set{EnsureChildControls();
txtDate.Text = value;}
}
To Render, all you need is this which is the simple way to do it. You can render the way you have it, but that is beyond my knowledge, and I see no practical purpose for it at the moment. The Atrribute tags in your RenderFunction, move them to your init function where you created the control, and keep them in groups.
protected override void Render(HtmlTextWriter writer)
{RenderContents(writer)
}
'OnInit Example, I made a table, added a tablerow, added a cell, and placed the textbox inside the cell.
'Make a Table Tag
table = New Table();
table.Width = 100
table.CellSpacing = 0;
table.CellPadding=0;
table.Style.Add(HtmlTextWriterStyle.Width, "100px");
table.Attribute.Add("border", "0");
controls.Add(table);
tr = New TableRow();
table.controls.add(tr)
td = New TableCell();
td.Style.Add(HtmlTextWriterStyle.TextAlign, "left")
td.Style.Add(HtmlTextWriterStyle.PaddingLeft, "5px");
tr.controls.Add(td)
txtDate = new TextBox(); txtDate.Enabled = false; txtDate.Text = [Text]; 'In vb, this is how you call the Property Value Text. [Text], [Width], [BorderColor], not sure how in CS, but it should be closetxtDate.Width = 90;
txtDate.Style.Add(HtmlTextWriterStyle.Width, "90px") td.Controls.Add(txtDate);- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Monday, June 23, 2008 1:10 PM