Why can't controls in Templates be referenced via their parent? - asp.net

I've been wondering to why you have to use FindControl to reference the checkbox in the Login1's LayoutTemplate. Example:
var login1CheckBox1 = (CheckBox)Login1.FindControl("CheckBox1");
I would expect to be able to do something along the lines of:
var login1CheckBox1 = Login1.LayoutTemplate.CheckBox1;
In the case of the Repeater below, it is obvious, because there can be n number of CheckBoxes.
But for the Login control, it doesn't seem to make sense. Why wouldn't this be implemented differently?
<asp:Login ID="Login1" runat="server">
<LayoutTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" />
</LayoutTemplate>
</asp:Login>
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" />
</ItemTemplate>
</asp:Repeater>
Does anyone have any light to shine on this?

A control added to a page via markup is defined in the designer partial class, generally, at design time.
A control added to a template is generally instantiated programmatically within the control's collection of controls.
Since the control added to the template does not exist at compile-time in the definition of that control, it would be rather impossible to achieve the syntax you're aiming for.
When creating a page in markup, we're using the IDE's facilities to generate a partial class. When defining a template in markup, we're simply setting the value of the ITemplate for that control.

Related

ASP.NET closing tag

When I use autocompletion in VisualStudio 2010 within my .aspx application, there are different default completions at closing control tags:
<asp:CheckBox />
<asp:Label></asp:Label>
Is there a explaination for this behaviour?
<asp:CheckBox></asp:CheckBox>
<asp:Label />
Wouldn't be invalid.
This is because ASP.NET's Label control is decorated with the ParseChildrenAttribute, with ParseChildren(false) while CheckBox isn't.
You can support the same behavior whith your custom controls, for example, with the following code, Visual Studio will behave like Label if you use MyControl in the web form editor:
[ParseChildren(false)]
public class MyControl : WebControl
{
...
}
The label closing is like that
<asp:Label runat="server"></asp:Label>
because usually we type something between
<asp:Label runat="server" ID="lblOne">better start programming now</asp:Label>
that is not the case for checkbox, that we type inside of it
<asp:CheckBox runat="server" Text="enable" ID="cbOne" />
We have on both elements the Text field, why on the one we prefer to write out side... Look at this example, on Label, or On other similar controls the text that we may have to write may include characters that are not allowed inside the Text Property, maybe a complex css style or what ever... The check box from the other side is only include a small text (yes, not, something like that)
<asp:Label ID="lblLabel" runat="server">
This is a <b>"label"</b>
<br />And one more line
</asp:Label>
and more example that compiles
<asp:Label ID="lblLabel" runat="server">
This is a <b>"label"</b>
<br />And one more line
<asp:Literal runat="server" ID="ltrOneMore">One more Control Inside</asp:Literal>
</asp:Label>
---but this is not compile--
<asp:Label ID="lblLabel2" runat="server"
Text="This is a <b>"label"</b>
<br /> and one more line"
/>
At the final end is a decision that the makes make - maybe we need to ask them for the real real reason.
Now this is also not compile
<asp:CheckBox runat="server" ID="cbMyChbx">one<asp:CheckBox>
check box when is render on page is use two controls, one input and one label, so they maybe need to help user to understand that the text is not going on the input control.
<asp:CheckBox />
Because the element has no content, you can close the tag with /> instead of using a separate closing tag
<asp:Label></asp:Label> or <asp:Label />
Displays static text on a Web Forms page and allows you to manipulate it programmatically.
Learn more about it Web Server Control
All the answers above are valid, but something additional. All the asp controls are eventually rendered as HTML controls and that also defines how the asp controls behave. For e.g. it is not necessary that text in a label is always set as
<asp:Label runat="server" ID="lblOne">better start programming now</asp:Label>
it can be also done as follows
<asp:Label runat="server" ID="lblOne" Text="better start programming"></asp:Label>
now both are correct format, so it is not valid to say that any control which needs content will have a separate closing tag. It also depends on how it rendered in HTML. for e.g by default asp Label is rendered as a span and doesnt conform to XHTML standards. Hope this makes it clear, always think of how it will be rendered and ASP tries to adhere to what eventually will be rendered.
cheers

Reusing ASP.NET Controls in Multiple Views

Is it possible to reuse asp.net controls in multiple views within a MultiView? I would like to provide my customers the option to view and entry form as either a ASP.NET Wizard or as a Form depending on their preference. Most of my research has resulted in numerous hits for MVC, but I'm using WebForms and can't find a definitive answer either way.
My theory is that this should be possible, but since the control is already defined elsewhere on the page, I ought to be able to simple tell it to re-display the same control at a different location.
For Example something like this perhaps:
<asp:MultiView ID="mv" runat="server" ActiveViewIndex="0">
<asp:View ID="WizardView" runat="server">
<asp:Wizard ID="wizzy" runat="server" ActiveStepIndex="0">
<WizardSteps>
<asp:WizardStep ID="WizardStep1" runat="server">
<!-- Wrapped in PlaceHolder goodness :P -->
<asp:PlaceHolder ID="wPH1" runat="server">
<asp:Label ID="MyLabel" runat="server" Text="Hello Stackies"></asp:Label>
</asp:PlaceHolder>
</asp:WizardStep>
</WizardSteps>
</asp:Wizard>
</asp:View>
<asp:View ID="FormView" runat="server">
<form action="#" method="post" id="wizzyform">
<!-- I WANT TO REUSE THIS CONTROL HERE -->
<asp:PlaceHolder ID="fPH1" runat="server"></asp:PlaceHolder>
</form>
</asp:View>
</asp:MultiView>
UPDATE WITH ANSWER!!
I simply added some PlaceHolders to my Markup and created a toggle button in my VB.NET Codebehind with the following.
Protected Sub ToggleView() Handles ViewToggleBtn.Click
If RequestWizard_mv.ActiveViewIndex = 0 Then
ViewToggleBtn.Text = "Toggle Wizard View"
RequestWizard_mv.ActiveViewIndex = 1
fPH1.Controls.Add(wPH1)
ElseIf RequestWizard_mv.ActiveViewIndex = 1 Then
ViewToggleBtn.Text = "Toggle Form View"
RequestWizard_mv.ActiveViewIndex = 0
wPH1.Controls.Add(fPH1)
End If
End Sub
WOOT!! :D SO HAPPY!! You have no idea how much pain this saves me :P
Note: I've noticed it doesn't maintain state very well, but super easy fix compared to re-writing double the code >.<
At least, you can have one instance of Label in your code-behind and add it programmatically to the desired place by condition using placeholders in both places.
Also you can make a new user control, and place all the logic that covers your Label there. You will still have 2 instances of this control, but you will design your Label once.

Why does Page.ParseControl not create control inherited from the correct base class?

I dynamically create a User Control from XML via XSLT. Output is a string with a content like this:
<%# Control Language="C#" AutoEventWireup="true" Inherits="Library.Web.UI.GeneratedFormBase, MyAssembly" %>
<div class="myCssClass">
<asp:TextBox ID="d" runat="server" OnTextChanged="OnTextChanged" />
<asp:Label runat="server" AssociatedControlID="SomeName" AccessKey="n">Label Text</asp:Label>
<asp:TextBox ID="SomeName" runat="server" OnTextChanged="OnTextChanged" />
<asp:Label runat="server" AssociatedControlID="SomeOtherName">Welcome</asp:Label>
<asp:TextBox ID="SomeOtherName" runat="server" OnTextChanged="OnTextChanged" />
<asp:Button ID="OK" runat="server" OnClick="ButtonClick" Text="Save" />
</div>
I now use Page.ParseControl(theGeneratedString) to create this control dynamically.
The type that is declared in Inherits is existing and can be found. If I declare another (i.e. non-existing) type there, a Parser Error Exception is thrown, so I am totally convinced that the parser looks for this type and finds it.
Nevertheless, the Control that is generated from the ParseControl is of type System.Web.UI.Control and not of the control that is stated (and obviously also parsed and located) in the Inherits-declaration.
Why is that and how can I ensure that the control is of the correct type?
Okay, after using a bit reflector it seems obvious why the Control is of the 'wrong' class. So ParseControl is simply the wrong method to do this. The correct one is LoadControl, but to use it I need to provide the generated form via a VirtualPathProvider. So it's a lot more work to get the control to parse correctly, but when using this approach the control is loaded, parsed, compiled and derived from the correct type.

Duplicate repeaters, identical UpdatePanels

Perhaps I'm making a faulty assumption here, but this has me stumped.
I've got to set up two identical repeaters in two different places in the same control. I want to avoid changing the names of controls so I can use the same functions on the front end (and actually, if there's a better way to have two identical repeaters in two different places other than a straight copy and paste, that'd be great). But for simplicity's sake, I've broken down the two as follows:
<asp:Repeater ID="rptTest" runat="server">
<ItemTemplate>
<asp:UpdatePanel runat="server" ID="updTestPanel">
<ContentTemplate>
<asp:TextBox ID="txtTest" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:TextBox ID="txtTest2" runat="server" />
</ItemTemplate>
</asp:Repeater>
<asp:Repeater ID="rptTest2" runat="server">
<ItemTemplate>
<asp:UpdatePanel runat="server" ID="updTestPanel">
<ContentTemplate>
<asp:TextBox ID="txtTest" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:TextBox ID="txtTest2" runat="server" />
</ItemTemplate>
</asp:Repeater>
Here's the thing: txtTest2 is fine being repeated in both repeaters, but txtTest throws the following errors:
Error 4 'txtTest' is already declared as 'Protected WithEvents txtTest As System.Web.UI.WebControls.TextBox' in this class.
Error 5 'Private Overloads Function __BuildControltxtTest() As System.Web.UI.WebControls.TextBox' has multiple definitions with identical signatures.
Error 8 'txtTest' is already declared as 'Protected WithEvents txtTest As System.Web.UI.WebControls.TextBox' in this class.
Is there a way to do what I'm trying to do, or do I need to rethink how I'm calling in asynchronous data in the repeater?
Without knowing too much as to what you are trying to do, the approach you have will work - but you cannot have two controls with the same name on the page. They are all in 'page' scope, and hence will complain.
What I would suggest is to have the methods be different for each textbox inside the repeater, but have them call different methods. In those methods, you can just pass the texbox values to a centralized method which will actually do the work. This way, you don't have to repeat the code, all you are doing is making two different functions that are the pass-thrus to your centralized method..
If you have controls that are DataBound (Repeater, DataList, FormVeiw, etc.) and under the updatepanel, these controls will have page level scope. You have to give them unique IDs, as I don't think that there is another work around for this problem. If you notice these controls are available on the page, without using FindControl.

Override FormView Templates

By default the FormView control creates html like :
ID <asp:TextBox ID="IdTextBox" runat="server" Text='<%# Eval("ID") %>' />
<br />
Name <asp:TextBox ID="NameTextBox" runat="server" Text='<%# Eval("Name") />
I prefer:
<ol class="form-layout">
<li><asp:Label AssociatedControl="IdTextBox" runat="server">ID:</aspLabel><asp
....
</ol>
My plan is to create a new control ( OrderedListFormView ) that inherits the FormView and overrides the method that generates the default "crap" html. I have been unable to find the method. Can anyone help? Do you have a better solution that costs $0 dollars?
I would prefer to change the default behavior at design time.
You sound like you have the ASP.NET form blues. Have you tried ASP.NET MVC? It gives you far better control of your rendered HTML, and you can mix it in with existing ASP.NET applications.
Try using Control Adapters to change the rendered HTML from a FormView, there is a tool kit and are pretty easy to code
http://weblogs.asp.net/scottgu/archive/2006/09/08/CSS-Control-Adapter-Toolkit-Update.aspx
http://msdn.microsoft.com/en-us/magazine/cc163543.aspx

Resources