I have a Custom Web Control that is derived from Panel. In my aspx markup for the control, I have a public event EventHandler called SubmitButtonClicked
<cc1:CreditCard ID="CustomCreditCardPopupPanel" runat="server"
SubmitButtonClicked="CustomCreditCardPopupPanel_SubmitClick"> </cc1:CreditCard>
Here is the code for the custom web control (Shortened for clarity). When the web control is instantiated, the EventHandler SubmitButtonClicked is always null. How do I pass in the name of the event that I want to bind to the Button called BtnSubmit?
[DefaultProperty("Text"),
AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal),
ToolboxData("<{0}:CreditCard runat=server></{0}:CreditCard>")
]
public class CreditCard: Panel {
public event EventHandler SubmitButtonClicked;
public Button BtnSubmit { get; set; }
protected override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
this.BtnSubmit.Click += new EventHandler(SubmitButtonClicked); // SubmitButtonClicked is always null
}
protected void SubmitButtonClicked_Clicked(Object sender, EventArgs e) {
if (SubmitButtonClicked != null) {
SubmitButtonClicked(sender, e);
}
}
}
You must have
this.BtnSubmit.Click += new EventHandler(SubmitButtonClicked_Clicked);
And also, OnPreRender event could be too late. Maybe you should assign the button event in Init, or Load event
Turns out that the best way to handle what I want to do is to derive my class from CompositeControl.
MSDN CompositeControl
Example from Link:
// Register.cs
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 Samples.AspNet.CS.Controls
{
[
AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level=AspNetHostingPermissionLevel.Minimal),
DefaultEvent("Submit"),
DefaultProperty("ButtonText"),
ToolboxData("<{0}:Register runat=\"server\"> </{0}:Register>"),
]
public class Register : CompositeControl
{
private Button submitButton;
private TextBox nameTextBox;
private Label nameLabel;
private TextBox emailTextBox;
private Label emailLabel;
private RequiredFieldValidator emailValidator;
private RequiredFieldValidator nameValidator;
private static readonly object EventSubmitKey =
new object();
// The following properties are delegated to
// child controls.
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The text to display on the button.")
]
public string ButtonText
{
get
{
EnsureChildControls();
return submitButton.Text;
}
set
{
EnsureChildControls();
submitButton.Text = value;
}
}
[
Bindable(true),
Category("Default"),
DefaultValue(""),
Description("The user name.")
]
public string Name
{
get
{
EnsureChildControls();
return nameTextBox.Text;
}
set
{
EnsureChildControls();
nameTextBox.Text = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description(
"Error message for the name validator.")
]
public string NameErrorMessage
{
get
{
EnsureChildControls();
return nameValidator.ErrorMessage;
}
set
{
EnsureChildControls();
nameValidator.ErrorMessage = value;
nameValidator.ToolTip = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The text for the name label.")
]
public string NameLabelText
{
get
{
EnsureChildControls();
return nameLabel.Text;
}
set
{
EnsureChildControls();
nameLabel.Text = value;
}
}
[
Bindable(true),
Category("Default"),
DefaultValue(""),
Description("The e-mail address.")
]
public string Email
{
get
{
EnsureChildControls();
return emailTextBox.Text;
}
set
{
EnsureChildControls();
emailTextBox.Text = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description(
"Error message for the e-mail validator.")
]
public string EmailErrorMessage
{
get
{
EnsureChildControls();
return emailValidator.ErrorMessage;
}
set
{
EnsureChildControls();
emailValidator.ErrorMessage = value;
emailValidator.ToolTip = value;
}
}
[
Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The text for the e-mail label.")
]
public string EmailLabelText
{
get
{
EnsureChildControls();
return emailLabel.Text;
}
set
{
EnsureChildControls();
emailLabel.Text = value;
}
}
// The Submit event.
[
Category("Action"),
Description("Raised when the user clicks the button.")
]
public event EventHandler Submit
{
add
{
Events.AddHandler(EventSubmitKey, value);
}
remove
{
Events.RemoveHandler(EventSubmitKey, value);
}
}
// The method that raises the Submit event.
protected virtual void OnSubmit(EventArgs e)
{
EventHandler SubmitHandler =
(EventHandler)Events[EventSubmitKey];
if (SubmitHandler != null)
{
SubmitHandler(this, e);
}
}
// Handles the Click event of the Button and raises
// the Submit event.
private void _button_Click(object source, EventArgs e)
{
OnSubmit(EventArgs.Empty);
}
protected override void RecreateChildControls()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
Controls.Clear();
nameLabel = new Label();
nameTextBox = new TextBox();
nameTextBox.ID = "nameTextBox";
nameValidator = new RequiredFieldValidator();
nameValidator.ID = "validator1";
nameValidator.ControlToValidate = nameTextBox.ID;
nameValidator.Text = "Failed validation.";
nameValidator.Display = ValidatorDisplay.Static;
emailLabel = new Label();
emailTextBox = new TextBox();
emailTextBox.ID = "emailTextBox";
emailValidator = new RequiredFieldValidator();
emailValidator.ID = "validator2";
emailValidator.ControlToValidate =
emailTextBox.ID;
emailValidator.Text = "Failed validation.";
emailValidator.Display = ValidatorDisplay.Static;
submitButton = new Button();
submitButton.ID = "button1";
submitButton.Click
+= new EventHandler(_button_Click);
this.Controls.Add(nameLabel);
this.Controls.Add(nameTextBox);
this.Controls.Add(nameValidator);
this.Controls.Add(emailLabel);
this.Controls.Add(emailTextBox);
this.Controls.Add(emailValidator);
this.Controls.Add(submitButton);
}
protected override void Render(HtmlTextWriter writer)
{
AddAttributesToRender(writer);
writer.AddAttribute(
HtmlTextWriterAttribute.Cellpadding,
"1", false);
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
nameLabel.RenderControl(writer);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
nameTextBox.RenderControl(writer);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
nameValidator.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
emailLabel.RenderControl(writer);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
emailTextBox.RenderControl(writer);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
emailValidator.RenderControl(writer);
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.AddAttribute(
HtmlTextWriterAttribute.Colspan,
"2", false);
writer.AddAttribute(
HtmlTextWriterAttribute.Align,
"right", false);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
submitButton.RenderControl(writer);
writer.RenderEndTag();
writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.Write(" ");
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();
}
}
}
Related
Sorry for my query but I am just a beginner in using UserControl:
Why do MouseClickEvent of a UserControl doesn't get inherited by the controls (e.g Labels) inside it?
To show you how I instantiate the UserControl inside a flowLayoutPanel:
studentItemList[] listItem = new studentItemList[dt.Rows.Count];
for (int i = 0; i < listItem.Length; i++)
{
listItem[i] = new studentItemList();
listItem[0].Anchor = AnchorStyles.Right;
listItem[i].MouseDoubleClick += StudentPrev;
listItem[i].StudentID = dt.Rows[i].Field<string>(0);
listItem[i].StudentName = dt.Rows[i].Field<string>(1) + ", " + dt.Rows[i].Field<string>(2) + " " + dt.Rows[i].Field<string>(3);
listItem[i].StudentEmail = dt.Rows[i].Field<string>(4);
listItem[i].StudentStatus = dt.Rows[i].Field<string>(5);
flowLayoutPanelStudents.Controls.Add(listItem[i]);
}
studentItemList.cs:
public partial class studentItemList : UserControl
{
public studentItemList()
{
InitializeComponent();
}
private string _studID, _studName, _studEmail, _status;
public string StudentID
{
get { return _studID; }
set { _studID = value; studentNo.Text = value; }
}
public string StudentName
{
get { return _studName; }
set { _studName = value; studentName.Text = value; }
}
private void studentNo_Click(object sender, EventArgs e)
{
}
public string StudentEmail
{
get { return _studEmail; }
set { _studEmail = value; studentEmail.Text = value; }
}
public string StudentStatus
{
get { return _status; }
set { _status = value; status.Text = value; }
}
private void label1_Click(object sender, EventArgs e)
{
}
}
Label.Autosize is set to true and DockStyles are set to Left.
Although, the MouseEvent get's triggered when the parent Panel of the UserControl is clicked.
What's the reason behind this?
You need to wire up all controls that may receive a click event.
If all controls in yout user control are added before the control is instantiated (e.g. design-time) then you can add event handlers in the user control's constructor.
If the user control has controls added/removed at run-time then you'll need to wire up ControlAdded and ControlRemoved events to wire/unwire events.
Not found anything that directly answers my problem, so hopefully someone can shed some light on it.
I have two Composite Controls, lets call them BudgetTable and BudgetTableItem, where BudgetTable contains a list of BudgetTableItem.
So far everything works so long as I add new RowItems in the HTML View - when I add one programmatically it appears, but doesn't survive postback.
I can only assume I'm doing something boneheaded with ViewState, and would appreciate any pointers!
Thanks in advance.
The HTML:
<hea:BudgetTable runat="server" ID="btTest" MaximumFundingAvailable="7000" CssClass="bob">
<Items>
<hea:BudgetTableItem runat="server" Description="Test1" />
<hea:BudgetTableItem runat="server" Description="Test2" />
<hea:BudgetTableItem runat="server" Description="Test3" />
</Items>
</hea:BudgetTable>
The code behind:
[PersistenceMode(PersistenceMode.InnerProperty)]
[ParseChildren(true)]
public class BudgetTableItem : CompositeControl {
private TextBox _description = new TextBox();
private TextBox _cost = new TextBox();
private CheckBox _heaFunded = new CheckBox();
/*public delegate void AddRow();
public delegate void RemoveRow(BudgetTableItem item);
public event AddRow AddNewRow;
public event RemoveRow RemoveNewRow;*/
public string ItemName {
get {
var viewstate = ViewState["ItemName"];
return (viewstate is string) ? (string)viewstate : "default";
}
set {
ViewState["ItemName"] = value;
}
}
public bool ShowRemoveRow {
get {
var viewstate = ViewState["ShowRemoveRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowRemoveRow"] = value;
}
}
public bool ShowAddRow {
get {
var viewstate = ViewState["ShowAddRow"];
return (viewstate != null && viewstate is bool) ? (bool)viewstate : false;
}
set {
ViewState["ShowAddRow"] = value;
}
}
public string Description {
get {
return _description.Text;
}
set {
_description.Text = value;
}
}
public decimal Cost {
get {
decimal cost =0;
decimal.TryParse(_cost.Text, out cost);
return cost;
}
set {
_cost.Text = value.ToString();
}
}
public bool HeaFunded {
get {
return _heaFunded.Checked;
}
set {
_heaFunded.Checked = value;
}
}
protected override void CreateChildControls() {
Controls.Clear();
HtmlTableCell tableCell1 = new HtmlTableCell();
HtmlTableCell tableCell2 = new HtmlTableCell();
HtmlTableCell tableCell3 = new HtmlTableCell();
HtmlTableCell tableCell4 = new HtmlTableCell();
tableCell1.Attributes.Add("class", "col1");
tableCell2.Attributes.Add("class", "col2");
tableCell3.Attributes.Add("class", "col3");
tableCell4.Attributes.Add("class", "col4");
tableCell1.Controls.Add(_description);
tableCell2.Controls.Add(_cost);
tableCell3.Controls.Add(_heaFunded);
/*if (ShowAddRow || ShowRemoveRow) {
Button addNewButton = new Button();
addNewButton.Text = (ShowAddRow) ? "Add Row" : "Remove";
if (ShowAddRow) {
addNewButton.Click += new EventHandler(addNewButton_Click);
}
if (ShowRemoveRow) {
addNewButton.Click += new EventHandler(removeButton_Click);
}
tableCell4.Controls.Add(addNewButton);
}
else{*/
tableCell4.InnerHtml = " ";
//}
Controls.Add(tableCell1);
Controls.Add(tableCell2);
Controls.Add(tableCell3);
Controls.Add(tableCell4);
}
/*void addNewButton_Click(object sender, EventArgs e) {
if (AddNewRow != null) {
AddNewRow();
}
}*/
/*void removeButton_Click(object sender, EventArgs e) {
if (RemoveNewRow != null) {
RemoveNewRow(this);
}
}*/
protected override void RecreateChildControls() {
EnsureChildControls();
}
public override void RenderBeginTag(HtmlTextWriter writer) {
writer.Write("<tr>");
}
public override void RenderEndTag(HtmlTextWriter writer) {
writer.Write("</tr>");
}
}
Controls, custom or otherwise that require a ViewState and wish to receive events should be created in Init.
Http is stateless. Your entire page with all its controls is recreated on every postback. Controls that you add in the design view, are added to your designer.cs file, and created for you. When you add controls yourself, you must write code to recreate the controls on every PostBack that occurs later.
You can use the session to remember which controls were added by code and add them on later PostBacks.
I've created a custom WebControl that implements a simple message box that can display at the top of a web page. Similar to how YouTube displays messages on their pages. My problem is passing the Click event from any button I add to the box down to the ASPX page.
Below is the code for the WebControl. I think I have handling the click events right, but when I add this code to my page, the click event never gets called, although Page_Load does.
Here's the code in the APSX page:
<rt:ConfirmationBox ID="ConfirmationBox1" runat="server" BoxType="Info" BoxButtons="OkayCancel" OnOkayClicked="ConfirmationBoxOkayClicked"
Text="Click OK to close." />
Here's the code in the code behind page:
protected void ConfirmationBoxOkayClicked(object sender, EventArgs e)
{
ConfirmationBox1.BoxButtons = ConfirmationBoxButtons.None;
ConfirmationBox1.BoxType = ConfirmationBoxType.Success;
ConfirmationBox1.Text = "You clicked OK!";
}
Here's the WebControl code:
public enum ConfirmationBoxType
{
Hidden,
Success,
Warn,
Error,
Info
}
public enum ConfirmationBoxButtons
{
None,
Okay,
Cancel,
OkayCancel
}
[DefaultProperty("Text")]
[ToolboxData("<{0}:ConfirmationBox ID=\"ConfirmationBox1\" runat=server></{0}:ConfirmationBox>")]
public class ConfirmationBox : WebControl
{
private static readonly ILog Log = LogManager.GetLogger(typeof(ConfirmationBox));
private Button _okayButton;
private Button _cancelButton;
public event EventHandler OkayClicked;
public event EventHandler CancelClicked;
public virtual void OnOkayClicked(object sender, EventArgs eventArgs)
{
if (OkayClicked != null)
OkayClicked(sender, eventArgs);
}
public virtual void OnCancelClicked(object sender, EventArgs eventArgs)
{
if (CancelClicked != null)
CancelClicked(sender, eventArgs);
}
protected override void OnPreRender(EventArgs e)
{
_okayButton = new Button {ID = "ConfirmBoxOkayButton", CssClass = "button", Text = "OK"};
_okayButton.Click += new EventHandler(OnOkayClicked);
_cancelButton = new Button {ID = "ConfirmBoxCancelButton", CssClass = "button", Text = "Cancel"};
_cancelButton.Click += new EventHandler(OnCancelClicked);
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
var s = (String)ViewState["Text"];
return (s ?? String.Empty);
}
set
{
ViewState["Text"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("Hidden")]
public ConfirmationBoxType BoxType
{
get
{
return (ConfirmationBoxType)ViewState["BoxType"];
}
set
{
ViewState["BoxType"] = value;
}
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("None")]
public ConfirmationBoxButtons BoxButtons
{
get
{
return (ConfirmationBoxButtons)ViewState["BoxButtons"];
}
set
{
ViewState["BoxButtons"] = value;
}
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Id, "alerts");
base.AddAttributesToRender(writer);
}
protected override void RenderContents(HtmlTextWriter writer)
{
if (Site != null && Site.DesignMode)
{
writer.Write("[" + ID + "]");
}
else
{
if (BoxType == ConfirmationBoxType.Hidden)
return;
var theme = HttpContext.Current.Profile["UserTheme"].ToString();
writer.AddAttribute(HtmlTextWriterAttribute.Id, "confirmBox");
writer.AddAttribute(HtmlTextWriterAttribute.Class, "rt-alert " + RenderBoxType());
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.AddAttribute(HtmlTextWriterAttribute.Src, string.Format("{0}/{1}/pixel.gif", ResolveUrl("~/App_Themes"), (string.IsNullOrEmpty(theme)) ? "Default" : theme));
writer.AddAttribute(HtmlTextWriterAttribute.Class, "icon");
writer.AddAttribute(HtmlTextWriterAttribute.Alt, "Alert icon");
writer.RenderBeginTag(HtmlTextWriterTag.Img);
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Class, "rt-alert-content");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write(Text);
writer.RenderEndTag();
writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
writer.AddAttribute(HtmlTextWriterAttribute.Class, "close");
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, "$(\"#alerts\").hide()");
writer.RenderBeginTag(HtmlTextWriterTag.Button);
writer.Write("close");
writer.RenderEndTag();
if (BoxButtons != ConfirmationBoxButtons.None)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "rt-alert-buttons");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
if (BoxButtons == ConfirmationBoxButtons.Okay || BoxButtons == ConfirmationBoxButtons.OkayCancel)
_okayButton.RenderControl(writer);
if (BoxButtons == ConfirmationBoxButtons.Cancel || BoxButtons == ConfirmationBoxButtons.OkayCancel)
_cancelButton.RenderControl(writer);
writer.RenderEndTag();
}
writer.RenderEndTag();
}
}
private string RenderBoxType()
{
switch (BoxType)
{
case ConfirmationBoxType.Success:
return "rt-alert-success";
case ConfirmationBoxType.Warn:
return "rt-alert-warn";
case ConfirmationBoxType.Error:
return "rt-alert-error";
case ConfirmationBoxType.Info:
return "rt-alert-info";
}
return string.Empty;
}
}
Create a separate method for your custom event handler, like this:
protected virtual void OnOkayClicked(EventArgs e)
{
if (OkayClicked!= null)
OkayClicked(this, e);
}
Change the name of the button click event and make it protected, like this:
protected void OkayButton_Click(object sender, EventArgs e)
{
//call your event handler method
this.OnOkayClicked(EventArgs.Empty);
}
Test this out, and see if it makes a difference.
I've created a customize web control with the combination of a Label, TextBox and RequiredFieldValidator. To done this, I create a class Field that inherit a Table Control.
namespace WebHRIS.Controls
{
public class Field : Table
{
private Label lblField;
private TextBox tbField;
private RequiredFieldValidator rfvField;
private string _text;
private string _invalidMessage;
private string _clientScript;
private string _controlID;
public virtual string LabelText
{
get { return _text; }
set { _text = value; }
}
public virtual string InvalidMessage
{
get { return _invalidMessage; }
set { _invalidMessage = value; }
}
public virtual string ClientScript
{
get { return _clientScript; }
set { _clientScript = value; }
}
public virtual string ControlID
{
get { return _controlID; }
set { _controlID = value; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
TableRow tr = new TableRow();
TableCell tc = new TableCell();
lblField = new Label();
lblField.Text = _text;
tc.Controls.Add(lblField);
tr.Cells.Add(tc);
tbField = new TextBox();
tbField.ID = _controlID + this.ID;
tc = new TableCell();
tc.Controls.Add(tbField);
tr.Cells.Add(tc);
rfvField = new RequiredFieldValidator();
rfvField.ControlToValidate = tbField.ID;
rfvField.ErrorMessage = this.InvalidMessage;
rfvField.EnableClientScript = (this.ClientScript.ToLower() != "false");
tc = new TableCell();
tc.Controls.Add(rfvField);
tr.Cells.Add(tc);
this.Rows.Add(tr);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
lblField.RenderControl(writer);
}
}
}
This is how I used this control
<%# Register TagPrefix="udc" Namespace="WebHRIS.Controls" Assembly="WebHRIS" %>
<udc:Field ID="fSample" runat="server" LabelText="Sample : " InvalidMessage="ErrorMessage"
ClientScript="false" ControlID="tb" />
Note that this is only a partial code. Now, I'm having a problem like this.
I want to eliminate the 'Sample : ' text. T.I.A
At a glance, I think you're getting the second line of text in you Render method:
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
lblField.RenderControl(writer);
}
lblField is the Label control - I would bet that the Label is getting written a second time by the call to lblField.RenderControl(writer). Try removing that line and see if your control will render properly.
I have my own TextBox2 class that derives from TextBox. I want to add a state called TextBlock and I want the VisualStateManager to go to that state when the IsTextBlock property/dependency property is true. When this is true, I want to change the style of the text box to be readonly and look just like a TextBlock but be able to select the text to be copyable. Is this possible? Is there a better way?
Something like that:
[TemplateVisualState(Name = "TextBlock", GroupName = "ControlType")]
[TemplateVisualState(Name = "TextBox", GroupName = "ControlType")]
public class TextBox2 : TextBox
{
public TextBox2()
{
DefaultStyleKey = typeof (TextBox2);
Loaded += (s, e) => UpdateVisualState(false);
}
private bool isTextBlock;
public bool IsTextBlock
{
get { return isTextBlock; }
set
{
isTextBlock = value;
UpdateVisualState(true);
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
UpdateVisualState(false);
}
internal void UpdateVisualState(bool useTransitions)
{
if (IsTextBlock)
{
VisualStateManager.GoToState(this, "TextBlock" , useTransitions);
}
else
{
VisualStateManager.GoToState(this, "TextBox" , useTransitions);
}
}
}
HTH