I want to build a server control that inherits from System.Web.UI.WebControls.MultiView.
The control will contain a collection of server controls that inherit from System.Web.UI.WebControls.View in turn. However, when I add a single view to the control's View collection, nothing gets rendered...
public class WizardMultiview : System.Web.UI.WebControls.MultiView
{
// field
private WizardStart _start;
override CreateChildControls()
{
this._start = new WizardStart(); // custom view
this._start.ID = "WizardStart1";
this.Views.Add(this._start);
this.ActiveViewIndex = 0;
}
override Render(HtmlTextWriter writer)
{
// NOTE: at this point the control can't render itself.
}
}
Then, within the Default.aspx.cs I do:
public void Page_Load(object sender, EventArgs e)
{
My.Controls.WizardMultiview view = new My.Controls.WizardMultiview();
this.Panel1.Controls.Add(view); // this is a Panel on the Default.aspx page
}
The custom View control looks like this:
public class WizardStart : System.Web.UI.WebControls.View
{
override Render(HtmlTextWriter writer)
{
writer.WriteLine("I am the starting point");
}
}
When I add this control an ASPX page, nothing happens. But if I create a MultiView, and add the MultiView to a CompositeControl's Control Collection and add the view to this MultiView, it works fine? I'm sure what I want to achieve is possible?
Related
I've try to extend SingleLineText field on WFFM on Sitecore. This field will have CustomValidator. But ServerValidate event does not fire when page postbacked. The snipped code below.
public class SingleLineText : Sitecore.Form.Web.UI.Controls.SingleLineText
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
var validator = new CustomValidator() { Display = ValidatorDisplay.None };
validator.ServerValidate += this.Validator_ServerValidate;
this.generalPanel.Controls.Add(validator);
}
protected void Validator_ServerValidate(object source, ServerValidateEventArgs args)
{
// does not fire
var validator = source as IValidator;
args.IsValid = this.IsValid(validator);
}
}
The same code works fine on ustom user control field which has ascx.
You will want to move your validation code to a new class that implements FormCustomValidator.
public class MySingleLineTextValidator : FormCustomValidator
{
protected override bool EvaluateIsValid()
{
if (!String.IsNullOrEmpty(base.ControlToValidate))
{
Control controlToValidate = this.FindControl(base.ControlToValidate);
//Code to validate
}
return false;
}}
Then you will need add a BaseValidator Item in the WFFM Validation Folder, usually this path; /sitecore/system/Modules/Web Forms for Marketers/Settings/Validation. Add the assembly and class to the item.
Now against your custom Field, add the your new BaseValidator item in the Validation field and that's it.
See this post of a wffm custom form validator for a full example
I've got a bit of an issue with creating a new control based on ASP.NET's ImageButton control. Everything works as expected, except for the click handler that is being hooked up in the control's OnInit override. Basically, clicking the custom image button just refreshes the page, never hitting the handler.
Now, I know this is something stupid I've done or just not understood, but I can't for the life of me figure this out. All the articles, questions and forum posts I've found on event handling issues for controls is for child controls, rather than ones that inherit from existing control types and have their own predefined handlers.
The following code is what I've written:
public class WebPaymentButton : ImageButton
{
public string DisabledImageUrl { get; set; }
public string TermsAcceptClass { get; set; }
protected override void OnPreRender(EventArgs e)
{
Page.ClientScript.RegisterClientScriptResource(typeof (WebPaymentButton), "PaymentModule.Scripts.WebPaymentButtonScript.js");
}
protected override void OnInit(EventArgs e)
{
CssClass = "WebPaymentButton";
if (!string.IsNullOrWhiteSpace(TermsAcceptClass))
{
Attributes["data-TermsClass"] = TermsAcceptClass;
}
if (!string.IsNullOrWhiteSpace(DisabledImageUrl))
{
Attributes["data-DisabledImageUrl"] = ResolveUrl(DisabledImageUrl);
}
Click += WebPaymentButton_Click;
base.OnInit(e);
}
private void WebPaymentButton_Click(object sender, ImageClickEventArgs e)
{
HttpContext.Current.Response.Redirect("http://dummy_payment_page_in_place_of_code", true);
}
}
I've tried hooking the handler up in the OnLoad and also switching it to run after the base.OnInit/OnLoad calls. Nothing has solved the handler issue. Can anyone point me in the right direction?
In case it helps, here is the markup for the button on the page:
<pm:WebPaymentButton runat="server" ImageUrl="~/pay-now.png" DisabledImageUrl="~/not-pay-now.png" TermsAcceptClass="TermsCheckbox" ID="MainPayButton" />
Have you tried overriding the OnClick event handler instead of hooking up to a new event handler?
Remove the Click += WebPaymentButton_Click line from OnInit and remove the WebPaymentButton_Click function, then add the following code to your class instead:
protected override void OnClick(ImageClickEventArgs e)
{
base.OnClick(e);
HttpContext.Current.Response.Redirect("http://dummy_payment_page_in_place_of_code", true);
}
I have a user control on the master page and I would like to pass in a value into that user control from the subpage, how would I be able to pass the values?
This control is in the master page
<%# Register TagPrefix="test" TagName="Data" Src="controls/TEST.ascx" %>
This code variable is within the user control
public partial class Controls_TEST : System.Web.UI.UserControl
{
private string _Title;
public string Title
{
get { return _Title; }
set { _Title = value; }
}
}
Code within the subpage
public partial class sub_page : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Controls_Test m = LoadControl("~/Controls/TEST.ascx");
m.Title = "TEST";
}
}
Note the sample code within subpage does not work because it cannot find that user control within the subpage.
I've tried Page.Master.FindControl and it also does not work for me. PLease help.
Use properties to communicate from your Page to your MasterPage and use properties to communicate from your MasterPage to the UserControl.
To get a reference to the control in your MasterPage you should provide a public property that returns it:
For example(in MasterPage):
public Controls_Test MyControl
{
get
{
return Controls_TEST1;
}
}
And you can call this property from one of your ContentPages in this way(f.e. if your master's type is named "SiteMaster"):
protected void Page_Load(object sender, EventArgs e)
{
((SiteMaster)Page.Master).MyControl.Title = "TEST";
}
As a rule of thumb: the more you encapsulate your controls, the more robust ,failsafe, maintanable and extendable your code will be.
Hence it would be better to provide only access to the Title rather than to the whole UserControl.
In MasterPage:
public String Title
{
get
{
return Controls_TEST1.Title;
}
set
{
Controls_TEST1.Title = value;
}
}
In the ContentPage:
((SiteMaster)Page.Master).Title = "TEST";
On this way you could change the logic and controls in your UserControl and MasterPage without having problems in your pages that already have accessed the UserControl directly.
I have my own Control1 which is dynamically added as child control to Control2 which implements INamingContainer in CreateChildControls() of control2.
Control1 itself implements IPostBackEventHandler. But RaisePostBackEvent() method is never called on Control1, despite I do call postback method from JavaScript.
And yes, there are other controls which implement IPostBackEventHandler interface on the page.
What did I miss?
What could cause the issue?
UPDATE: Control1 is always created exactly the same way and assigned exactly the same ID in Control2
it looks like this in Control2:
protected override void CreateChildControls()
{
if(!this.DesignMode)
{
Control1 c = new Control1();
c.ID = "FIXED_ID";
}
base.CreateChildControls();
}
UPDATE2:
Control1:
public class Control1: Control, IPostBackEventHandler
{
...
protected virtual void RaisePostBackEvent(string eventArgument)
{
if(!String.IsNullOrEmpty(eventArgument))
{
// Some other code
}
}
}
if I add line
Page.RegisterRequiresRaiseEvent(c);
In CreateChildControls() in Control2 then this method is being called but always with null eventArgument.
UPDATE3:
In JavaScript on some onClick event I do the following:
__doPostBack(Control1.UniqueID,'commandId=MyCommand');
where Control1.UniqueID is of course substituted with real uniqueID during rendering. I checked, this script is being called.
Can you show us the source code of first control? Anyway there is a simple example.
public class TestControl2 : CompositeControl
{
protected override void CreateChildControls()
{
base.CreateChildControls();
if (!DesignMode)
this.Controls.Add(new TestControl());
}
}
public class TestControl : WebControl, IPostBackEventHandler
{
public TestControl() : base(HtmlTextWriterTag.Input) { }
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
writer.AddAttribute(HtmlTextWriterAttribute.Type, "button");
writer.AddAttribute(HtmlTextWriterAttribute.Name, base.UniqueID);
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, null));
writer.AddAttribute(HtmlTextWriterAttribute.Value, "Submit Query");
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
// Raise post back event
}
}
Edit
Why you are generating the post back script out of the control and manually? You have to use Page.ClientScript.GetPostBackEventReference method. It generates and includes some necessary inline and embedded scripts to the page.
Why you are deriving your class from Control? It's good for those controls which don't have any user interface.
From MSDN
This is the primary class that you
derive from when you develop custom
ASP.NET server controls. Control does
not have any user interface (UI)
specific features. If you are
authoring a control that does not have
a UI, or combines other controls that
render their own UI, derive from
Control. If you are authoring a
control that does have a UI, derive
from WebControl or any control in the
System.Web.UI.WebControls namespace
that provides an appropriate starting
point for your custom control.
You have to derive your control from WebControl class as follows.
public class TestCtl : WebControl, IPostBackEventHandler
{
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
// Add onclick event.
writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackEventReference(this, "Arguments"));
}
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
throw new NotImplementedException();
}
}
I'm going to guess that it's the "dynamically added as child control to Control2" that is the issue, but without any code it's pretty hard to diagnose.
When during the page lifecycle are you dynamically adding it? Are you recreating the dynamic control in the exact same way, with the same ID, after the postback?
I have a menu of report links in my master page. I need to append an ID to the end of each whenever the user changes a value on the child page. What's a good way to accomplish this?
UPDATE: I should have mentioned that the child update is happening inside an UpdatePanel, meaning the master page is not reloaded when the change happens.
A MasterPage is really a child control of the page which it controls. You can control a MasterPage like any other control on your page (almost). All you need to do is get a reference to it.
You add a property to the code of your MasterPage, so its code may look something like this:
public partial class _default : System.Web.UI.MasterPage
{
protected string m_myString = string.Empty;
public string myString
{
get { return m_myString; }
set { m_myString = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
Then you have to cast the this.Master property to your MasterPage
public partial class index : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Cast here to get access to your MasterPage
_default x = (_default)this.Master;
x.myString = "foo";
}
}
In response to your UPDATE:
The updated panel could write the ID to a hidden field and the menu events could look for that hidden fields in Request.Form["fieldName"].
Note that you shouldn't fieldName.Text because ASP.NET does a bad job of returning the right value for fields that have been AJAXed.