I am developing a web application where I would like to perform a set of validations on a certain field (an account name in the specific case).
I need to check that the value is not empty, matches a certain pattern and is not already used.
I tried to create a UserControl that aggregates a RequiredFieldValidator, a RegexValidator and a CustomValidator, then I created a ControlToValidate property like this:
public partial class AccountNameValidator : System.Web.UI.UserControl {
public string ControlToValidate {
get { return ViewState["ControlToValidate"] as string; }
set {
ViewState["ControlToValidate"] = value;
AccountNameRequiredFieldValidator.ControlToValidate = value;
AccountNameRegexValidator.ControlToValidate = value;
AccountNameUniqueValidator.ControlToValidate = value;
}
}
}
However, if I insert the control on a page and set ControlToValidate to some control ID, when the page loads I get an error that says Unable to find control id 'AccountName' referenced by the 'ControlToValidate' property of 'AccountNameRequiredFieldValidator', which makes me think that the controls inside my UserControl cannot resolve correctly the controls in the parent page.
So, I have two questions:
1) Is it possible to have validator controls inside a UserControl validate a control in the parent page?
2) Is it correct and good practice to "aggregate" multiple validator controls in a UserControl? If not, what is the standard way to proceed?
Addressing your second question first- I don't think it's a good idea to "aggregate" validators together this way unless you include the controls you're validating in the user control. Too much work for not enough payoff.
You could fix this problem by exposing properties on your AggregatedValidator to set the names of the controls to validate, and pass in the ClientID of those controls you want validated.
I believe ASP.NET expects the ControlToValidate ID to be in the same naming container. You can probably override the validation method and use Parent.FindControl.
EDIT: This might be a good place to use a CompositeControl rather than a UserControl. They are designed for just this kind of aggregation. But you might have a similar NamingContainer issue.
Related
I have a UserControl (ascx) that, depending on the user's credentials, will load another UserControl (ascx). Currently the control to be loaded, contains a special navigation menu.
I am using this code:
UserControl jmNav =
(UserControl)Page.LoadControl("~/controls/client/jmNavigation.ascx");
Then, after some more code, I'm telling it to load, like this:
SBarTopWelcome.Controls.Add(jmNav);
The problem is, that I'm getting an "object reference not set to instance of an object" error.
Yes, the path is correct - as I tried it like this, as well (in all variations):
UserControl jmNav = (UserControl)Page.LoadControl("/client/jmNavigation.ascx");
This one (and its variants) tells me it doesn't exist.
So! Any thoughts?
One helpful solution is to add <%# Register %> to your parent control. Yes, I know it's in your parent page, but it should also be in your control.
If you do this, you should be able to Strongly-Type your control. For example, a control with a class name of MyControl would be:
MyControl controlVar = (MyControl)this.LoadControl("MyControl.aspx");
If you are able to get the stronly-defined variable, you should have no problems.
Inside SideBar.ascx add a place holder named SideBarTopWelcomePlaceHolder.
<asp:PlaceHolder ID="SideBarTopWelcomePlaceHolder" runat="server"/>
Then load jmNavigation UserControl to SideBarTopWelcomePlaceHolder like this.
Control jmNav =
Control Page.LoadControl("~/controls/client/jmNavigation.ascx");
SideBarTopWelcomePlaceHolder.Add(jmNav);
HA! I'm such a DORK! I was declaring the "SideBarWelcome" within a control like this:
public Control sideBarTopWelcome
{
get { return Page.FindControl("SideBarTopWelcome"); }
}
When I should have done it like this:
public Control sideBarTopWelcome
{
get { return FindControl("SideBarTopWelcome"); }
}
Without Page. Thank you anyway, guys. I appreciate it.
How to Access Controls from UserControls in ASPX page?
For example:
I want to access gridview which is in usercontrol on ASPX page.
Please help me.
Try this :
GridView GridView1 = (GridView)WebUserControl1.FindControl("GridView1");
Where WebUserControl1 is ID of use control on .aspx page.
Hope this helps..
The best way is to provide properties in your UserControl that you can access.
For example:
public GridView UserGrid
{
get
{
return GridView1;
}
}
But the question is why you need this.
Rule of thumb: Only expose as few as possible. On that way your code will be most robust and readable. So it would e.g. better to expose it's DataSource rather than the complete GridView.
On the other hand, if you want your page to react on events in your UserControl, it should provide custom events(e.g. UserDeleted) that your page then can handle.
Page-UserControl-Commmunication
Because the controls now nothing about eachother at the same level, you have to use the parent page to get it. Try this logic:
Create a property referring to your parent page (the page your control usually is in (might be different because of layering of controls)
Create a property on your page referring to the usercontrol the grid is in, or link to that grid directly.
page.aspx
public UserControl UserGridControl
{
get;
set;
}
userControl.ascx
public Page ParentPage
{
get;
set;
}
Example call:
Instantiate the properties first. After that, use the following statement to access anything from that control (as an example I used Foo() here, to use as a dummy method, but it seems it was unclear to someone):
otherControl.ascx:
this.ParentPage.UserGridControl.Foo();
EDIT: Want to have a direct code example to be able do it from the page only? See Tim Schmelters answer. If you need a way to call the grid from another user control as well. Use mine.
I would like to read the Form value of a control (e.g TextBox), i.e 'Request.Form["[Control_Name_Here]"]. The problem with using say TextBox.Text is because if you explicity set it yourself in the Page_Load, there is no way you can get back the 'original value' submitted in the form.
As you know, Asp.Net generates a unique ID/Name for the control. The Request.Form is based on the name attribute of a control. Each webcontrol has a ClientID property, however this does not match the name. The name seems to be almost like the ClientID, having $ instead of _. Is there a way to easily get the value from the form, without resorting to having to replace the _ to a $?
And this should also cater for other naming-conventions, because as from Asp.Net you can also choose to have a control's id statically-generated, rather than dynamically.
It sounds to me like you're not looking for the .ClientID property, but the .UniqueID property of the Control.
See: MSDN
Edit: Also, is there a reason you're always setting the .Text property within the page load? Instead of for example check the Page.IsPostBack property instead and only set the .Text if it's false?
I personally use jquery to find the control and read and set the value
GetFormValue = function (idName) {
var srchP = '[id='+idName+']';
var ctrl = $(srchP);
if (ctrl != null)
return ctrl.val();
return null;
}
so assume th id name in server part is txMytext
and it will be .....$txMytext in client
and by calling GetFormValue('txMytext') in client side you cna get the value of control
dont foget to use jquery library
In my case I would like to dynamically add validators to my control based on given logic. For each control I first check something in my DB and if it goes aout that field is required I would like to add requiredField to that control. I firt iterate through each control and if its required I add attribute required="true".
I added this code but it doens work I mean nothing happens, none validation is being made.
if(gc.Attributes["controlid"] != null)
{
RequiredFieldValidator validator = new RequiredFieldValidator();
validator.ControlToValidate = gc.Attributes["controlid"];
validator.ErrorMessage = gc.Attributes["errormessage"];
this.Controls.Add(validator);
}
Thanks for any suggestions.
You also have to add it to the Page's validators collection in order for the server side validation to occur. Adding it just to the page controls collection as you did is what is needed to get the JavaScript validation to get rendered to the browser.
Page.Validators.Add(validator);
Are you adding your Validator control to the same container as the control it validates? Validator controls require the target control to be in the same INamingContainer.
Context: ASP.NET 3.5 / C#
Hi,
I created a user control
public partial class MyControl : UserControl
{
// EDIT: example first used "UniqueId" as property name, which was wrong.
public Guid MyId { get; set; }
// ...
}
and this example usage
<uc1:MyControl
ID="myControl"
MyId="443CBF34-F75F-11DD-BE2F-68C555D89123"
runat="server" />
Steps:
Add this control to a web form (aspx)
Expected result:
the HTML for the user control is added, a unique value (corresponding to Guid.NewGuid()) for MyId is set in the ASPX HTML at design-time as the MyId attribute value.
Actual result:
the HTML for the user control is added, a unique value for MyId is not set in the HTML at design time for the MyId Attribute value.
If this is not possible:
Workaround 1: Would it be possible to achieve this using a server control? How?
Workaround 2: is it possible to achieve this using a UserControl design-mode task?
Clarification:
persisting the property value is not an issue, since it never changes for a control intance and is automatically set by ASP.NET through the control declaration in the aspx page.
the MyId attribute does not need to be rendered at runtime.
Gr B!
Custom Design-time Control Features in Visual Studio .NET
You have a couple problems here, but first I will answer your questions about the workarounds.
No you are already using a server control.
No design-mode is to just make the lives of the developer easy, it doesn't effect anything else
You have two problems here. There is already a property called UniqueID I don't know if you were trying to overload that, but the question wasn't clear. The second problem is that your UniqueID essentially not getting stored anywhere. Try the following code:
public Guid UniqueId {
get { return (Guid)ViewState["MyUserControlUniqueId"]; }
set { ViewState["MyUserControlUniqueId"] = value; }
}
That will store the GUID in the ViewState so that you can retrieve it on post backs.
Update: Given your comment you need to override/use this method to add attributes to the rendered content.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.webcontrol.addattributestorender.aspx
If I understand your question correctly, you are exposing a property on your user control called MyId. This allows you to set the property wherever you put that control.
What you also want, is for the rendered HTML to also include this attribute and value.
If that's the case, the property MyId is not passed through to the HTML, it's only because the user control has MyId as a property that it's visible in the designer.
In your user control you will have defined the markup that gets rendered.
So for example if you have:
<asp:Panel runat="Server" Id="myControlDiv">Some other content</asp:Panel>
You can then in your controls prerender event (or wherever else you choose) put
myControlDiv.Attributes.Add("MyId", SomeGuid.ToString())
Which will then get output in the HTML as
<div id="generatedID" MyID="443CBF34-F75F-11DD-BE2F-68C555D89123">Some other content</div>
So you just want a unique ID generated that you only ever use in design time?
Why not override Object.GetHasCode();
And then exposure this as a property?