I have created a custom server control. So far this control renders some html in the webpage. On submit of the page i need to take the values entered in the textbox of the server control and call some webservice to validate the input of the user. i don't want to write this code in code behind of the page that this control is used in. I want all the validations to be written in the server control itself and if validation fails, Page.IsValid should be set to false. If the user input value in server control is valid Page.IsValid will be true.
I am trying to achieve is the same functionality as google recaptcha. All user needs to do to use this control is to user the control in the page. user entered value is correct or incorrect is handled in the control itself and in the code behind of the page, there is only Page.IsValid. Here is the page on google that explains this
http://code.google.com/apis/recaptcha/docs/aspnet.html
and i have also used the google recaptcha and it works as expected. I also want to build same kind of functionality for my server control, Please help, if it is possible.
Thank's for answering the questions. I found the solution. Here is the entire code of the server control. The trick was to implement IValidator. It gives us two property and one metod. ErrorMessage and IsValid properties and Validate method. I wrote all the validation code in Validate method and set this.IsValid. This solved the problem.
[ToolboxData("<{0}:MyControl runat=server></{0}:MyControl>")]
public class MyControl : WebControl, IValidator
{
protected override void RenderContents(HtmlTextWriter output)
{
//Render the required html
}
protected override void Render(HtmlTextWriter writer)
{
this.RenderContents(writer);
}
protected override void OnInit(EventArgs e)
{
Page.Validators.Add(this);
base.OnInit(e);
}
public string ErrorMessage
{
get;
set;
}
public bool IsValid
{
get;
set;
}
public void Validate()
{
string code = Context.Request["txtCode"];
this.IsValid = Validate(code);//this method calls the webservice and returns true or false
if (!this.IsValid)
{
ErrorMessage = "Invalid Code";
}
}
}
You could incorporate the validator in the server control. It would need a server validate method to call the web service.
The net result would be a server control that you drop on the page, no other validators needed. if your control can't validate it's contents, then page.isvalid will be false.
Simon
Related
I am trying to pass a few parameters between two web pages
within the source page I have the following properties
private string _testString { get; set; }
public string TestString
{
get
{
return _testString;
}
}
In previous msdn examples the return type was always set to a UI element (textbox.text)
However I am trying to pass the value from a dynamically generated link button which is why I chose to use the private accessor
In the click event of the link button on the source page I have the following:
protected void RenderReportInNewPage(LinkButton lb)
{
_testString = lb.CommandArgument.ToString();
Response.BufferOutput = true;
Response.Redirect("~/stuff/testviewer.aspx");
}
On the target page I have the source page referenced in the aspx as follows:
<%# PreviousPageType VirtualPath="~/stuff/testviewer.aspx"%>
And then in the codebehind of the target page I have the following:
Textbox.Text = PreviousPage.TestString;
PreviousPage displays the public property TestString but it is always null (as I don't think it is getting set but not sure why)
Is is possible to set a private accessor (_teststring) and have that value reflected within the public property? I'd appreciate any suggestions on what I have done wrong.
-Cheers
Found the error. It was not in the setting of the property but in how I was invoking the target page. In order to pass the properties across I needed to user Server.Transfer instead of Response.Redirect
protected void RenderReportInNewPage(LinkButton lb)
{
_testString = lb.CommandArgument.ToString();
Response.BufferOutput = true;
Server.Transfer("~/ReportBuilder/viewer.aspx");
}
-cheers
I have a question about server controls VS. user controls (.ascx). Currently, when I write a user control, I want to be able to take advantage of using the AjaxControlToolKit DLL. In particular, I want my user control to be able to do partial post backs and use the various extenders (modalPopUp for example). My boss, though, prefers us to use server controls so that we can compile them into a DLL and use them in various applications. My question is: If I rewrite my user controls to be server controls, will I still be able to use the AjaxControlToolKit and all its features (asyn post backs and extenders)?
FYI: I am using Visual Studio 2010, AjaxControlToolkit 4.1.60919 and .Net 4.0
Yes, you'll be able to do this. Just inherit your control from the CompositeControl class interface and add any extender or control from the ACT project to the Controls collection the same way as you should do this with ordinal ASP.NET server controls. Also you can inherit existing control and implement INamingContainer interface but in this case you must call RenderChildren method manually from control's Render method:
[DefaultProperty("Text")]
[ToolboxData("<{0}:WatermarkedTextBox runat=server></{0}:WatermarkedTextBox>")]
public class WatermarkedTextBox : TextBox, INamingContainer
{
private AjaxControlToolkit.TextBoxWatermarkExtender _watermarkExtender;
public string WatermarkText
{
get
{
return ViewState["WatermarkText"] as string;
}
set
{
ViewState["WatermarkText"] = value;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
this._watermarkExtender = new AjaxControlToolkit.TextBoxWatermarkExtender
{
ID = "wte",
TargetControlID = this.ID,
WatermarkText = this.WatermarkText
};
this.Controls.Add(_watermarkExtender);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
RenderChildren(writer);
}
}
}
I am developing a custom server control, following is control's markup on my ASPX page,
<uc:NoteBook ID="nb1" runat="server">
<NotePages>
<uc:NotePage ID="p1" runat="server">
<asp:DropDownList ID="ddl1" runat="server"></asp:DropDownList>
</uc:NotePage>
</NotePages>
</uc:NoteBook>
Note that this control has NotePages property which is actually a collection of NotePage control. And NotePage control can have any type of children.
On the same aspx page, in Page_Load event handler, I am loading some items in DropDownList control,
if (!this.IsPostBack)
{
this.ddl1.Items.Add(new ListItem("Class-1", "C1"));
this.ddl1.Items.Add(new ListItem("Class-2", "C2"));
this.ddl1.Items.Add(new ListItem("Class-3", "C3"));
}
Problem:
Now problem is after Post Back, the DropDownList items get cleared. Which is clearly indicating I am missing some state management here.
Can anyone please guide my how to handle it?
Following is the control code.
public class NoteBook : CompositeControl
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public virtual List<NotePage> NotePages
{
get;
set;
}
public NoteBook()
{
this.NotePages = new List<NotePage>();
}
protected override void CreateChildControls()
{
foreach (var c in this.NotePages)
{
this.Controls.Add(c);
}
base.CreateChildControls();
}
}
[ParseChildren(false)]
public class NotePage : UserControl
{
}
Thanks.
You need to add the items when initializing the control not during the load event. Note: that the items need to always be added, not just when the page is not loading during a GET. By the time the load event has occurred the state has been initialized. See `Control Execution Lifecycle'
OK I solved it.
We just need to call the EnsureChildControls() method on control initialization, which causes child controls to be created before the ViewState/etc. things gets called.
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.EnsureChildControls();
}
I added above code in my NoteBook control.
I have an ASP.NET user control that is used in another use control. The parent user control uses data-binding to bind to a custom property of the child user control.
What method can I override or page event where I am ensured that the property state is set?
I think in a page it is PageLoaded versus the Page_Load override? I am looking for this in the user control because my property is always null even though it is set.
Thanks.
Example. This is in my user control. FilterEntryId is being bound from inside another user control:
protected int _filterEntry = -1;
public int FilterEntryId
{
get
{
return _filterEntry;
}
set
{
_filterEntry = value;
}
}
protected void Page_Load(dobject sender, EventArgs e)
{
FilterEntry always -1!!
}
The property is being set but never has value when Page_Load. The Page_LoadComplete may be the proper place but does not seem to be an option in user control. I've also tried Page_DataBind.
My hypothesis is that this is a page lifecycle issue but it may be something else.
Not sure what you need to do with that property but since you can't be sure when will be set. Can't you add your logic on the set of the property?
Another option would be a later event as PreRender.
public int FilterEntryId
{
get
{
return _filterEntry;
}
set
{
_filterEntry = value;
//HERE YOUR LOGIC
}
}
I want to be able to find the old value of a asp.net control (textbox, checkbox etc) without relying on events (e.g. OnTextChange event). Something like "someTextboxControl.OldText" would be perfect! I imagine that it is stored in the viewstate and need to somehow get at it via a custom control. Any ideas?
The answer provided by Shrage was helpful, but it took some additional searching to make this solution work. I placed his code into the code behind within the namespace of the page I was working on. Additionally I had to register the control, and change update the control in question.
Register extended textboxex control; this goes right below the page directive
<%# Register TagPrefix="group" Namespace="ESM_Web_Portal" Assembly="ESM Web Portal" %>
Update the texbox you want to extend in the aspx page
<group:TextBoxEx ID="txbEditPartNumber" runat="server" Text='<%# Bind("part_number") %>'></group:TextBoxEx>
Then in code behind I was able to use the extended TextBox control
protected void CheckForExistingPartNumber(object sender, ServerValidateEventArgs e)
{
CustomValidator cv = ((CustomValidator)sender);
TextBoxEx tb = (TextBoxEx)cv.Parent.FindControl(cv.ControlToValidate);
if (SupplyBLL.GetSupplyByPartNumber(e.Value) != null && tb.Text != tb.OldText)
{
e.IsValid = false;
}
}
public class TextBoxEx:System.Web.UI.WebControls.TextBox
{
public string OldText { get; set; }
protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
OldText = Text;
return base.LoadPostData(postDataKey, postCollection);
}
}