Updated Code
- From: Christophe Peillet <ChristophePeillet@xxxxxxxxxxxxx>
- Date: Tue, 10 Jan 2006 02:03:02 -0800
Steven:
Thank you for your response.
I normally place the value of properties in the ViewState, but in this case,
I choose to access the control's properties directly, since the underlying
control also adds it's value to the ViewState. I would be storing the
Textbox's 'Text' value in ViewState twice if I also added it here in this
composite control.
As per your advice, I have rearranged some of the code, and tried to remove
everything from the Render event, instead pushing pushing the relevant code
into CreateChildControls(). I have also moved the code where property values
are assigned to OnPreRender(), rather than the private SetRunTimeProperties().
For simplicity sake, I have also removed the custom designer. I have
included the full modified class below.
Unfortunately, my problem still persists. Whenever I make a change to any
of my custom properties (such as LabelText, which is defined in the parent
class, or TextboxText, which is defined in this class), these values are
changed in the underlying HTML code and appear at run time, but never change
in DesignMode and the Property Browser is never updated. This makes it
almost impossible to meaningfully create controls at DesignTime.
If I place some sort of rendering code in a Designer in the
'GetDesignTimeHtml()' method, does it mean I will need to duplicate all of my
rendering code in the Designer as well (I hate to have the same code in two
places)? The control should work without a designer at all, though,
shouldn't it? (I only created one to allow SmartTags support.)
If you can give me any other advice on why control's are not being refreshed
at DesignTime, it would be appreciated. I'm completely lost with this
problem, and am already behind schedule because of it. ;-(
Best regards, and thank you for your time.
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Web.UI.Design.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using Telerik.WebControls;
namespace Epson.EEE.Web.UI.FormControls
{
/// <summary>
/// An AJAX enabled TextBox control, which automatically applies the
Epson style guide to its appearance.
/// </summary>
/// <seealso cref="T:SupportTextBoxDesigner"/>
/// <seealso cref="T:SupportTextBoxActionList"/>
// ToDo: Restore Designer
// [Designer(typeof(SupportTextBoxDesigner))]
[DefaultProperty("Text")]
[DefaultEvent("TextChanged")]
[ToolboxData("<{0}:SupportTextBox runat=server></{0}:SupportTextBox>")]
public class SupportTextBox : SupportFormLabelledControl, INamingContainer
{
#region Internal Fields
// Any third-party or external controls that you wish to add to the
this
// control, such as buttons, labels, etc., should be declared here.
// Declare any required controls/objects
private CallbackTextBox m_txt;
private CallbackLabel m_lbl;
private IconPopupControl m_icn;
#endregion
#region Event Handlers
// Declare any events that will be raised by this control.
/// <summary>
/// Fires when the textbox's text content is changed, and focus is
lost from the control. (Please note that this event only fires when <see
cref="P:SupportTextBox.CallbackEnabled"/> is set to True.)
/// </summary>
[Category("Action")]
[Description("Fires when the text is changed. (Please note that
this event only fires when CallbackEnabled is set to True.)")]
public event EventHandler TextChanged;
#endregion
#region Constructor
// Default values for properties should ONLY be defined in the the
// class constructor. If you set properties elsewhere, such as in the
// OnLoad event, you will make the control insensitive to external,
// tag-level settings.
/// <summary>
/// Initializes a new instance of the <see cref="SupportTextBox"/>
class.
/// </summary>
public SupportTextBox()
{
// Set default values
this.SetDefaultValues();
}
#endregion
#region Protected Methods (Page Events)
/// <summary>
/// Raises the <see cref="E:System.Web.UI.Control.Init"></see> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"></see> object
that contains the event data.</param>
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
/// <summary>
/// Raises the <see cref="E:System.Web.UI.Control.Load"></see> event.
/// </summary>
/// <param name="e">The <see cref="T:System.EventArgs"></see> object
that contains the event data.</param>
protected override void OnLoad(EventArgs e)
{
// Call base Load method
base.OnLoad(e);
EnsureChildControls();
}
/// <summary>
/// Called by the ASP.NET page framework to notify server controls
that use
/// composition-based implementation to create any child controls
they contain
/// in preparation for posting back or rendering.
/// </summary>
protected override void CreateChildControls()
{
// Clear the control collection
Controls.Clear();
// Any dependant controls used in this custom control must
// be added to the control 'hierarchy'. If they are not added
// to the control collection, they will not be visible to other
// controls on the page.
// Instantiate any dependant controls
Table tbl = new Table();
m_txt = new CallbackTextBox();
m_lbl = new CallbackLabel();
m_icn = new IconPopupControl();
// Register any events associated with dependant controls
m_txt.TextChanged += new EventHandler(RaiseTextChanged);
// Create table object and format it through relevant method
tbl = CreateTable(this.LabelPosition);
// Add table to the control collection
Controls.Add(tbl);
// Add controls to the table control collection
switch (this.LabelPosition)
{
case Position.Left:
tbl.Rows[0].Cells[0].Controls.Add(m_lbl);
tbl.Rows[0].Cells[1].Controls.Add(m_txt);
if (this.Required)
{
tbl.Rows[0].Cells[1].Controls.Add(m_icn);
}
// Set relevant design properties
tbl.Rows[0].Cells[0].Width = new
Unit(this.LabelWidth.ToString());
break;
case Position.Top:
tbl.Rows[0].Cells[0].Controls.Add(m_lbl);
tbl.Rows[1].Cells[0].Controls.Add(m_txt);
if (this.Required)
{
tbl.Rows[1].Cells[0].Controls.Add(m_icn);
}
// Set relevant design properties
tbl.Rows[0].Cells[0].Width = new
Unit(this.LabelWidth.ToString());
break;
case Position.Right:
tbl.Rows[0].Cells[0].Controls.Add(m_txt);
if (this.Required)
{
tbl.Rows[0].Cells[0].Controls.Add(m_icn);
}
tbl.Rows[0].Cells[1].Controls.Add(m_lbl);
// Set relevant design properties
tbl.Rows[0].Cells[1].Width = new
Unit(this.LabelWidth.ToString());
break;
case Position.Bottom:
tbl.Rows[0].Cells[0].Controls.Add(m_lbl);
tbl.Rows[1].Cells[0].Controls.Add(m_txt);
if (this.Required)
{
tbl.Rows[1].Cells[1].Controls.Add(m_icn);
}
// Set relevant design properties
tbl.Rows[0].Cells[0].Width = new
Unit(this.LabelWidth.ToString());
break;
default:
Debug.Assert(false);
break;
}
// Call base method
base.CreateChildControls();
}
/// <summary>
/// Raises the <see cref="E:System.Web.UI.Control.PreRender"></see>
event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"></see> object
that contains the event data.</param>
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
// Associate dependent control properties with this control's
properties
m_lbl.CssClass = this.LabelCssClass;
m_lbl.Text = this.LabelText;
m_lbl.Visible = this.LabelVisible;
m_lbl.RadControlsDir = this.ScriptsPath;
m_lbl.CallbackEnabled = this.CallbackEnabled;
m_lbl.DisableAtCallback = this.DisableAtCallback;
m_lbl.Enabled = this.Enabled;
m_txt.MaxLength = this.TextboxMaxLength;
m_txt.ReadOnly = this.TextboxReadOnly;
m_txt.RadControlsDir = this.ScriptsPath;
m_txt.DisableAtCallback = this.DisableAtCallback;
m_txt.CallbackEnabled = this.CallbackEnabled;
m_txt.CssClass = this.TextboxCssClass;
m_txt.Enabled = this.Enabled;
m_icn.ImageUrl = this.WarningImageUrl;
m_icn.ImageAlign = this.ImageAlign;
m_icn.EmptyImageUrl = this.EmptyImageUrl;
m_icn.MessageStyle = this.MessageStyle;
m_icn.PopupText = this.PopupText;
m_icn.PopupTextResourceKey = this.PopupTextResourceKey;
m_icn.PopupTitle = this.PopupTitle;
m_icn.PopupTitleResourceKey = this.PopupTitleResourceKey;
m_icn.WarningIconVisible = this.WarningIconVisible;
m_icn.Enabled = this.Enabled;
m_icn.CssClass = this.WarningIconCssStyle;
}
/// <summary>
/// Renders the contents of the control to the specified writer.
This method is used primarily by control developers.
/// </summary>
/// <param name="output">A <see
cref="T:System.Web.UI.HtmlTextWriter"></see> that represents the output
stream to render HTML content on the client.</param>
protected override void RenderContents(HtmlTextWriter output)
{
EnsureChildControls();
// Create temporary HtmlTextWriter placeholder
StringBuilder stringBuilder = new StringBuilder();
StringWriter stringWriter = new StringWriter(stringBuilder);
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
// Render child controls
RenderChildren(htmlWriter);
// If you wish to make any modifications to the raw Html code
// before it is send to the output stream (for example, ensuring
// that the code is XHtml compliant, etc.), you can make the
// modifications to the 'rawHtml' field below. This code will
// then be sent to the real Html output stream.
string rawHtml = stringBuilder.ToString();
output.Write(rawHtml);
}
/// <summary>
/// Raised when the user changes the content of the textbox. This
event only fires when <see cref="P:SupportTextBox.CallbackEnabled"/> is set
to True.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance
containing the event data.</param>
protected void RaiseTextChanged(object sender, EventArgs e)
{
// ToDo: Is there a better way to do this (update properties
automatically)
this.TextboxText = ((CallbackTextBox)sender).Text;
// Make sure we are not running in DesignMode
if (!(this.DesignMode))
{
if (!(TextChanged == null))
{
this.TextChanged(sender, new EventArgs());
}
}
}
#endregion
#region Private Methods
/// <summary>
/// Sets the control's default values.
/// </summary>
private void SetDefaultValues()
{
// Set properties to default values
this.TextboxCssClass = SharedConstants.SupportForm_TextBoxStyle;
this.TextboxMaxLength = 0;
this.TextboxReadOnly = false;
this.TextboxText = string.Empty;
}
/// <summary>
/// Creates the table that will hold the relevant controls.
/// </summary>
/// <param name="labelPosition">The label position, which is used to
/// determine how the table should be arranged.</param>
/// <returns>A Table object</returns>
private Table CreateTable(Position labelPosition)
{
Table tbl = new Table();
// Set basic table properties
tbl.BorderStyle = BorderStyle.None;
tbl.BorderWidth = 0;
// Format table according to label position
switch (labelPosition)
{
case Position.Left:
tbl.Rows.Add(new TableRow());
tbl.Rows[0].Cells.Add(new TableCell());
tbl.Rows[0].Cells.Add(new TableCell());
break;
case Position.Top:
tbl.Rows.Add(new TableRow());
tbl.Rows[0].Cells.Add(new TableCell());
tbl.Rows.Add(new TableRow());
tbl.Rows[1].Cells.Add(new TableCell());
break;
case Position.Right:
tbl.Rows.Add(new TableRow());
tbl.Rows[0].Cells.Add(new TableCell());
tbl.Rows[0].Cells.Add(new TableCell());
break;
case Position.Bottom:
tbl.Rows.Add(new TableRow());
tbl.Rows[0].Cells.Add(new TableCell());
tbl.Rows.Add(new TableRow());
tbl.Rows[1].Cells.Add(new TableCell());
break;
default:
Debug.Assert(false);
break;
}
// Return results
return tbl;
}
#endregion
#region Public Properties
/// <summary>
/// Gets or sets the textbox CSS class.
/// </summary>
/// <value>The textbox CSS class.</value>
[Bindable(true)]
[Category("Textbox")]
[Description("The Css Class associated with the textbox.")]
[Localizable(false)]
public string TextboxCssClass
{
get
{
EnsureChildControls();
return m_txt.CssClass;
}
set
{
Debug.Assert(value != null, "Warning: TextboxCssClass
property is null!");
if (value != null)
{
EnsureChildControls();
m_txt.CssClass = value;
}
else
{
throw new NullReferenceException("TextboxCssClass can
not be assigned a null value.");
}
}
}
/// <summary>
/// Gets or sets a value indicating whether the textbox is read only.
/// </summary>
/// <value><c>true</c> if read only; otherwise, <c>false</c>.</value>
[Bindable(true)]
[Category("Textbox")]
[DefaultValue(typeof(bool), "False")]
[Description("Whether the textbox contents can be modified by users
or not.")]
[Localizable(false)]
public bool TextboxReadOnly
{
get
{
EnsureChildControls();
return m_txt.ReadOnly;
}
set
{
EnsureChildControls();
m_txt.ReadOnly = value;
}
}
/// <summary>
/// Gets or sets the textbox text.
/// </summary>
/// <value>The textbox text.</value>
[Bindable(true)]
[Category("Textbox")]
[DefaultValue(typeof(string), "")]
[Description("The text that will be displayed in the textbox.")]
[Localizable(true)]
[NotifyParentProperty(true)]
public string TextboxText
{
get
{
EnsureChildControls();
return m_txt.Text;
}
set
{
Debug.Assert(value != null, "Warning: TextboxText property
is null!");
if (value != null)
{
EnsureChildControls();
m_txt.Text = value;
}
else
{
throw new NullReferenceException("TextboxText can not be
assigned a null value.");
}
}
}
/// <summary>
/// Gets or sets the maximum length (in characters) of the text box
content.
/// </summary>
/// <value>The maximum length of the text box content.</value>
[Bindable(true)]
[Category("Textbox")]
[Description("The maximum number of characters that can be entered
in the textbox.")]
[Localizable(false)]
public int TextboxMaxLength
{
get
{
EnsureChildControls();
return m_txt.MaxLength;
}
set
{
EnsureChildControls();
m_txt.MaxLength = value;
}
}
#endregion
}
}
.
- References:
- Changed property values not reflected in DesignMode
- From: Christophe Peillet
- Designer Code for this control
- From: Christophe Peillet
- RE: Designer Code for this control
- From: Steven Cheng[MSFT]
- Changed property values not reflected in DesignMode
- Prev by Date: RE: new menu control is very slow
- Next by Date: RE: Designer Code for this control
- Previous by thread: RE: Designer Code for this control
- Next by thread: RE: Designer Code for this control
- Index(es):