Disable EventValidation for single control, is it possible? - asp.net

I know this is a very debated topic, and usually when you are thinking about this as a solution you might want to rethink your UI logic.
I know I can pass validation using ClientScriptManager.RegisterForEventValidation. But, I'd really like to know. Is it possible to remove event validation for a single control? Is there a way work around for this?
I'm modifying a DropDownList, from the client side after it's rendered.

The SupportsEventValidation attribute is not inherited for subclasses, so if you create a subclass of DropDownList, don't apply that attribute to the subclass, and use the subclass on your page, you will have a control that doesn't trigger event validation, even if event validation is enabled on the page.
public Class DynamicDropDownList : DropDownList
{
}
http://msdn.microsoft.com/en-us/library/system.web.ui.supportseventvalidationattribute%28v=VS.110%29.aspx

Another way to handle this:
Set the property EnableViewState="False" on the particular element.
Reasoning: If you are using JavaScript to change this value outside of ASP.NET's control, then ViewState is just getting in your way at that point. Stop using it for that control.

The short answer to your question is: No, there is no way to do this. You must disable EventValidation for the entire page.
There are various workarounds... If you really don't want to disable EventValidation, store the selected value in a hidden field and restore the state of the DropDownList (or maybe just clear selection?).
If you need all the values added client-side, you have to send those up using some other method anyway, because they will not be present in the server-side control. Those values are not posted!

I found it easier to replace the control with the HTML equivalent with runat="server", you can then retrieve the value the of old fashion way with Request.Forms["id"]. There will be no validation done, so be careful on storing or processing the data.
The other option is to override the Render on the page and use Page.ClientScript.RegisterForEventValidation with all the possible answers (not nice).
something like this
protected override void Render(HtmlTextWriter writer)
{
this.Page.ClientScript.RegisterForEventValidation(ddlRisk.ID, "a");
this.Page.ClientScript.RegisterForEventValidation(ddlRisk.ID, "b");
this.Page.ClientScript.RegisterForEventValidation(ddlRisk.ID, "c");
base.Render(writer);
}

Related

How to get all validators in the page?

I thought RequiredFieldValidators, CustomValidators, and all other validators would live in Controls collection. Basically I have a User Control that has a number of validators in it, and I would like to get a handle on them to do stuff.
Page.Validators seem to return a list of IValidator objects, which are not what I am looking for.
Where can I get the list of all validators in a User Control?
The Page.Validators collection is your best bet; all validators implement IValidator, and in turn, BaseValidator, so you can use this do to that. Since the validator is a control, it's parent reference trail will contain a reference to the user control it lives in. It may require you doing something like:
if (validator.Parent.Parent.Parent.Parent is UserControl) { }
But that is the only way to figure that out. So a combination of Page.Validators, and checking the parent control tree is the only way, unless you look for specific validation groups that a validator implements, which also is another way (a property of BaseValidator, so you'll have to do a type check and cast.
There is one last potential option; you can override AddedControl, which executes on every control add, and check if the control is a validator, and then keep that control in a local collection like:
private List<BaseValidator> _vals = ..;
protected overrides void AddedControl(Control control, int index) {
if (control is BaseValidator)
_vals.Add((BaseValidator)control);
}
Then you would know which controls belong to that user control. I've done this with custom controls, not anything with user controls, so may not work exactly as I mentioned...
Since you're using ASP.NET validation controls you might be looking for a validation summary:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.validationsummary%28v=vs.100%29.aspx
You can do quite a bit with it fitting most usage scenarios, here's a simple example:
http://asp-net-example.blogspot.com/2008/10/validationsummary-example-how-to-use.html
Alternatively, Page.Validators would provide direct access.

asp.net linkbutton properties

I have an app that, based on the .text property in a linkbutton (which is set programmatically, typically "Add" or "Save") the system adds or saves to the database. The linkbutton is standalone and not within a gridview or anything like that. Now the customer just wants to see "Save" in all cases, which invalidates my logic. I would prefer to use the app's existing logic as much as possible. Unfortunately the linkbutton doesn't have a property such as
.nonvisibletext, so I'm wondering if it does have a property which I could put a string in that I don't use, and I'm looking at CommandName. I do use that in gridview processing, but not in linkbuttons.
Can I safely use CommmandName instead of Text? Or is there is internal usage of this property? I'm not finding anything in research so far that indicates one way or the other.
Thanks!
As per my knowledge, you can use the CommandName/Command Argument properties of the LinkButton without any problem. The only change would be that the "OnClick" event should be removed and "OnCommand" should be added.
Hope this Helps!!

Can I assume asp.net form's ID always being the same?

I want to submit a simple asp.net form in jQuery
can I assume
$("form[0]").submit()
always works, cross browser?
You mean something like this
$("#aspnetForm").submit()
Something like above would work cross browser as you said
The code you pasted is cross browser too. It won't work on ANY browser so maybe that counts as cross browser :-) just a joke
No, you can't assume this. $("form[0]").submit() will submit the first form on the page. However, you can have more than one form on an ASP.NET page, though only one of these forms can be a server-side form (with runat="server" attribute).
If what you want is to submit the server-side form on an ASP.NET page then I think the best way would be to do it in code-behind by registering a script. It's a bit more hassle, but should always work (and when there is no server-side form it will detect it). Something like this:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (this.Form != null)
{
string js = String.Format("$('#{0}').submit()", this.Form.ClientID);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Submit", js, true);
}
}
These will:
$("#aspnetForm").submit()
or
var theForm = document.forms['aspnetForm'];
theForm.submit()
If you know that this code will be triggered by an input or button element within the ASP.NET form, or if you can select a known input or button element within the ASP.NET form, you can use input.form.submit();.
Usage examples
this.form.submit();
or
$("#some_input_or_button").get(0).form.submit();
Although reading the input.form/button.form property does not use jQuery, it is at least as cross-browser since jQuery itself does this.
Benefit: This method allows you to avoid dependence on the form ID generated by ASP.NET's internals without having to add any extra wiring server-side.

Child Control Initialization in Custom Composite in ASP.NET

Part of the series of controls I am working on obviously involves me lumping some of them together in to composites. I am rapidly starting to learn that this takes consideration (this is all new to me!) :)
I basically have a StyledWindow control, which is essentially a glorified Panel with ability to do other bits (like add borders etc).
Here is the code that instantiates the child controls within it. Up till this point it seems to have been working correctly with mundane static controls:
protected override void CreateChildControls()
{
_panel = new Panel();
if (_editable != null)
_editable.InstantiateIn(_panel);
_regions = new List<IAttributeAccessor>();
_regions.Add(_panel);
}
The problems came today when I tried nesting a more complex control within it. This control uses a reference to the page since it injects JavaScript in to make it a bit more snappy and responsive (the RegisterClientScriptBlock is the only reason I need the page ref).
Now, this was causing "object null" errors, but I localized this down to the render method, which was of course trying to call the method against the [null] Page object.
What's confusing me is that the control works fine as a standalone, but when placed in the StyledWindow it all goes horribly wrong!
So, it looks like I am missing something in either my StyledWindow or ChildControl. Any ideas?
Update
As Brad Wilson quite rightly pointed out, you do not see the controls being added to the Controls collection. This is what the _panel is for, this was there to handle that for me, basically then override Controls (I got this from a guide somewhere):
Panel _panel; // Sub-Control to store the "Content".
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return _panel.Controls;
}
}
I hope that helps clarify things. Apologies.
Update Following Longhorn213's Answer
Right, I have been doing some playing with the control, placing one within the composite, and one outside. I then got the status of Page at event major event in the control Lifecycle and rendered it to the page.
The standalone is working fine and the page is inited as expected. However, the one nested in the Composite is different. It's OnLoad event is not being fired at all! So I am guessing Brad is probably right in that I am not setting up the control hierarchy correctly, can anyone offer some advice as to what I am missing? Is the Panel method not enough? (well, it obviously isn't is it?!) :D
Thanks for your help guys, appreciated :)
I don't see you adding your controls to the Controls collection anywhere, which would explain why they can't access the Page (since they've never been officially placed on the page).
I have always put the JavaScript calls on the OnLoad Function. Such as below.
protected override void OnLoad(EventArgs e)
{
// Do something to get the script
string script = GetScript();
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "SomeJavaScriptName", script);
// Could also use this function to determine if the script has been register. i.e. more than 1 of the controls exists
this.Page.ClientScript.IsClientScriptBlockRegistered("SomeJavaScriptName");
base.OnLoad(e);
}
If you still want to do the render, then you can just write the script in the response. Which is what the RegisterScriptBlock does, it just puts the script inline on the page.
Solved!
Right, I was determined to get this cracked today! Here were my thoughts:
I thought the use of Panel was a bit of a hack, so I should remove it and find out how it is really done.
I didn't want to have to do something like MyCtl.Controls[0].Controls to access the controls added to the composite.
I wanted the damn thing to work!
So, I got searching and hit MSDN, this artcle was REALLY helpful (i.e. like almost copy 'n' paste, and explained well - something MSDN is traditionally bad at). Nice!
So, I ripped out the use of Panel and pretty much followed the artcle and took it as gospel, making notes as I went.
Here's what I have now:
I learned I was using the wrong term. I should have been calling it a Templated Control. While templated controls are technically composites, there is a distinct difference. Templated controls can define the interface for items that are added to them.
Templated controls are very powerful and actually pretty quick and easy to set up once you get your head round them!
I will play some more with the designer support to ensure I fully understand it all, then get a blog post up :)
A "Template" control is used to specify the interface for templated data.
For example, here is the ASPX markup for a templated control:
<cc1:TemplatedControl ID="MyCtl" runat="server">
<Template>
<!-- Templated Content Goes Here -->
</Template>
</cc1:TemplatedControl>
Heres the Code I Have Now
public class DummyWebControl : WebControl
{
// Acts as the surrogate for the templated controls.
// This is essentially the "interface" for the templated data.
}
In TemplateControl.cs...
ITemplate _template;
// Surrogate to hold the controls instantiated from
// within the template.
DummyWebControl _owner;
protected override void CreateChildControls()
{
// Note we are calling base.Controls here
// (you will see why in a min).
base.Controls.Clear();
_owner = new DummyWebControl();
// Load the Template Content
ITemplate template = _template;
if (template == null)
template = new StyledWindowDefaultTemplate();
template.InstantiateIn(_owner);
base.Controls.Add(_owner);
ChildControlsCreated = true;
}
Then, to provide easy access to the Controls of the [Surrogate] Object:
(this is why we needed to clear/add to the base.Controls)
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return _owner.Controls;
}
}
And that is pretty much it, easy when you know how! :)
Next: Design Time Region Support!
Right, I got playing and I figured that there was something wrong with my control instantiation, since Longhorn was right, I should be able to create script references at OnLoad (and I couldn't), and Brad was right in that I need to ensure my Controls hierarchy was maintained by adding to the Controls collection of the composite.
So, I had two things here:
I had overriden the Controls property accessor for the composite to return this Panel's Controls collection since I dont want to have to go ctl.Controls[0].Controls[0] to get to the actual control I want. I have removed this, but I need to get this sorted.
I had not added the Panel to the Controls collection, I have now done this.
So, it now works, however, how do I get the Controls property for the composite to return the items in the Panel, rather than the Panel itself?

Dynamically added controls in Asp.Net

I'm trying to wrap my head around asp.net. I have a background as a long time php developer, but I'm now facing the task of learning asp.net and I'm having some trouble with it. It might very well be because I'm trying to force the framework into something it is not intended for - so I'd like to learn how to do it "the right way". :-)
My problem is how to add controls to a page programmatically at runtime. As far as I can figure out you need to create the controls at page_init as they otherwise disappears at the next PostBack. But many times I'm facing the problem that I don't know which controls to add in page_init as it is dependent on values from at previous PostBack.
A simple scenario could be a form with a dropdown control added in the designer. The dropdown is set to AutoPostBack. When the PostBack occur I need to render one or more controls denepending on the selected value from the dropdown control and preferably have those controls act as if they had been added by the design (as in "when posted back, behave "properly").
Am I going down the wrong path here?
I agree with the other points made here "If you can get out of creating controls dynamically, then do so..." (by #Jesper Blad Jenson aka) but here is a trick I worked out with dynamically created controls in the past.
The problem becomes chicken and the egg. You need your ViewState to create the control tree and you need your control tree created to get at your ViewState. Well, that's almost correct. There is a way to get at your ViewState values just before the rest of the tree is populated. That is by overriding LoadViewState(...) and SaveViewState(...).
In SaveViewState store the control you wish to create:
protected override object SaveViewState()
{
object[] myState = new object[2];
myState[0] = base.SaveViewState();
myState[1] = controlPickerDropDown.SelectedValue;
return myState
}
When the framework calls your "LoadViewState" override you'll get back the exact object you returned from "SaveViewState":
protected override void LoadViewState(object savedState)
{
object[] myState = (object[])savedState;
// Here is the trick, use the value you saved here to create your control tree.
CreateControlBasedOnDropDownValue(myState[1]);
// Call the base method to ensure everything works correctly.
base.LoadViewState(myState[0]);
}
I've used this successfully to create ASP.Net pages where a DataSet was serialised to the ViewState to store changes to an entire grid of data allowing the user to make multiple edits with PostBacks and finally commit all their changes in a single "Save" operation.
You must add your control inside OnInit event and viewstate will be preserved. Don't use if(ispostback), because controls must be added every time, event in postback!
(De)Serialization of viewstate happens after OnInit and before OnLoad, so your viewstate persistence provider will see dynamically added controls if they are added in OnInit.
But in scenario you're describing, probably multiview or simple hide/show (visible property) will be better solution.
It's because in OnInit event, when you must read dropdown and add new controls, viewstate isn't read (deserialized) yet and you don't know what did user choose! (you can do request.form(), but that feels kinda wrong)
After having wrestled with this problem for at while I have come up with these groundrules which seems to work, but YMMV.
Use declarative controls whenever possible
Use databinding where possible
Understand how ViewState works
The Visibilty property can go a long way
If you must use add controls in an event handler use Aydsman's tip and recreate the controls in an overridden LoadViewState.
TRULY Understanding ViewState is a must-read.
Understanding Dynamic Controls By Example shows some techniques on how to use databinding instead of dynamic controls.
TRULY Understanding Dynamic Controls also clarifies techniques which can be used to avoid dynamic controls.
Hope this helps others with same problems.
If you truly need to use dynamic controls, the following should work:
In OnInit, recreate the exact same control hierarchy that was on the page when the previous request was fulfilled. (If this isn't the initial request, of course)
After OnInit, the framework will load the viewstate from the previous request and all your controls should be in a stable state now.
In OnLoad, remove the controls that are not required and add the necessary ones. You will also have to somehow save the current control tree at this point, to be used in the first step during the following request. You could use a session variable that dictates how the dynamic control tree was created. I even stored the whole Controls collection in the session once (put aside your pitchforks, it was just for a demo).
Re-adding the "stale" controls that you will not need and will be removed at OnLoad anyway seems a bit quirky, but Asp.Net was not really designed with dynamic control creation in mind. If the exact same control hierarchy is not preserved during viewstate loading, all kinds of hard-to find bugs begin lurking in the page, because states of older controls are loaded into newly added ones.
Read up on Asp.Net page life cycle and especially on how the viewstate works and it will become clear.
Edit: This is a very good article about how viewstate behaves and what you should consider while dealing with dynamic controls: <Link>
Well. If you can get out of creating controls dynamicly, then do so - otherwise, what i whould do is to use Page_Load instead of Page_Init, but instead of placing stuff inside the If Not IsPostBack, then set i just directly in the method.
Ah, that's the problem with the leaky abstraction of ASP.NET web forms.
Maybe you'll be interested to look at ASP.NET MVC, which was used for the creation of this stackoverflow.com web site? That should be an easier fit for you, coming from a PHP (thus, pedal-to-the-metal when it comes to HTML and Javascript) background.
I think the answer here is in the MultiView control, so that for example the dropdown switches between different views in the multi-view.
You can probably even data-bind the current view property of the multiview to the value of the dropdown!
The only correct answer was given by Aydsman. LoadViewState is the only place to add dynamic controls where their viewstate values will be restored when recreated and you can access the viewstate in order to determine which controls to add.
I ran across this in the book "Pro ASP.NET 3.5 in C# 2008" under the section Dynamic Control Creation:
If you need to re-create a control multiple times, you should perform the control creation in the Page.Load event handler. This has the additional benefit of allowing you to use view state with your dynamic control. Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the Page.Load event, ASP.NET will apply any view state information that it has after the Page.Load event handler ends. This process is automatic.
I have not tested this, but you might look into it.

Resources