Locate HTML Element when it does not have the runat="server" attribute - c#

I have an ASP.NET C# website and I am attempting to retrieve the inner html from a HTML in my page when a button is clicked.
My Problem: I use the function FindControl() but it returns null when it should find the element. Why is this happening, what am I doing wrong?
My HTML page:
<%# Page Title="test" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="test.aspx.cs" Inherits="test" %>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="ActualContent">
<div class="regMainContainer mainContainer container">
<!-- Attempting to get the below div -->
<!-- Knowtice it does not have runat="server",
I would prefer not to do that if I dont need to -->
<div id="courseDiv" class="courseContainer">
</div>
</div>
</asp:content>
My Code that executes when a button is clicked(inside test.aspx.cs file:
HtmlGenericControl d = (HtmlGenericControl)FindControl("courseDiv");

FindControl can only find controls that has runat="server" attributes. The good news is that you can easily change you div to a panel, and add data that way.
the bad news is that this still won't let you access the innerhtml of the div, .net sees it as just a container for other controls.
The best way to do this would be some form of ajax, since your client side script would be able to read that contents and pass it to a server side method

You won't be able to use FindControl for something that's not marked with runat="server". This is because any of the elements not marked with runat="server" get parsed as one giant text literal at runtime. You can add runat="server" to any arbitrary html element, though.

Related

Page_Load of 2. user control never executes (website)

I am in the process of making a website that displays information in boxes.
There will be different pages with different combinations of boxes. They will have a lot of boxes in common.
Therefor, I am making the boxes as user controls to then put on the different pages. The different pages will also share a master page.
However, when starting development of the 2. box, I ran into a problem:
The Page_Load (or the whole code behind) of the 1. box runs fine, but the Page_Load og the 2. box gets ignored. This results in a lot of null values that makes the aspx file crash.
My CT1.aspx contains this to use the two user controls:
<%# Page Title="CustType1" Language="C#" MasterPageFile="~/MTCustomer/Master.master" AutoEventWireup="true" CodeFile="CT1.aspx.cs" Inherits="MTCustomer.CT1" %>
// Some HTML
<td ID="column1" style="width: 400px;">
<Box:CustomerInfoBoxAx runat="server" />
<Box:CustomerInfoBoxMt runat="server" />
</td>
// Some HTML
My Web.config contains this for the user controls to be usable:
<pages>
<controls>
<add tagPrefix="Box" tagName="InfoBoxA" src="~/Controls/InfoBoxA.ascx" />
<add tagPrefix="Box" tagName="InfoBoxB" src="~/Controls/InfoBoxB.ascx" />
</controls>
</pages>
My user control A looks lige this:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="InfoBoxA.ascx.cs" Inherits="Controls.InfoBoxA" %>
<% if (IsVisible("InfoBoxA") && Customer != null)
{ %>
<div>
<%-- Markup --%>
</div>
<% } %>
And box B looks like this:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="InfoBoxB.ascx.cs" Inherits="Controls.InfoBoxB" %>
<link rel="stylesheet" type="text/css" href="<%=VirtualPathUtility.ToAbsolute("~/Styles/InfoBoxStyle.css")%>">
<% if (IsVisible("InfoBoxB") && Customer != null)
{ %>
<div>
<%-- Markup --%>
</div>
<% } %>
I have tried to swap the order of the two user controls in the page.aspx, this also changed witch one had its Page_Load (or the whole code behind) ignored. Based on that, it looks like only the first code behind is executed, and the rest is ignored.
EDIT:
After following the exceptions that comes after the initial null reference exception, I can see that the Page.DataBind() in the first user control is still executing. This must mean that this is what causes the aspx file of both box one and two run. But how do I get around this?
Problem solved.
I removed Page.DataBind() from all user controls, and in the CT1.aspx.cs (the page code behind) i moved it from Page_Load() to OnLoadComplete().
By doing this, Page_Load() in all files have been executed before the Page.DataBind() is executed.

Getting A page can have only one server-side Form tag Error

I have done my MasterPage and create a new .aspx page with this MasterPage . but whenever I try to add a RadioButton to the .aspx page it's generate to me this error:
Control 'head_ctl00' of type 'RadioButton' must be placed inside a
form tag with runat=server.
and I have tried to add a form tag and this error came out !
A page can have only one server-side Form tag.
I'm confused how I can solve this problem ! any idea ?
in case you need my .aspx page :
<%# Page Title="" Language="C#" MasterPageFile="~/MySite.Master" AutoEventWireup="true" CodeBehind="Registration.aspx.cs" Inherits="MyWebsite.Registration" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<form id="frm" runat="server">
<asp:RadioButton runat="server"></asp:RadioButton>
</form>
</asp:Content>
You have inserted your RadioButton inside the head placeholder that has not the form tag in your MasterPage file. You should place RadioButton in another PlaceHolder like MainContent or FeaturedContent. Also you don't need the form tag in your ContentPages, The form tag on the master page will be sufficient.

How can I get my asp:TreeView control to recognize the TreeNodeCheckChanged method I wrote?

I'm having a really frustrating issue with a TreeView control in a Web Form. I'm using C# on Visual Studio, and, admittedly, this is my first project on the platform, so there are a lot of caveats I'm finding I'm not aware of.
The page I'm working on isn't that complicated. In the body of WebPage.aspx, I have an empty TreeView control declared, along with a Label to display output (for testing) and a Button to cause a postback:
<asp:TreeView ID="SimpleTreeView" runat="server">
</asp:TreeView>
<asp:Label ID="StatusLabel" runat="server">No change yet.</asp:Label>
<asp:Button ID="SaveButton" runat="server" Text="Save Changes" PostBackUrl="~/WebPage.aspx" />
I populate the TreeView programmatically within the Page_Load method of my WebPage class, based on data in our SQL server. That part works like a charm.
Now, I want to define the event handler for the TreeView's TreeNodeCheckChanged event. Firstly, YES, I know that the event does not fire immediately when a checkbox is changed; 99% of everything I can find on the Internet about this is people complaining about that. For my application, waiting until the button is clicked is fine.
I've followed what the MSDN article on the event does, by adding the OnTreeNodeCheckChanged attribute to the TreeView control:
<asp:TreeView ... OnTreeNodeCheckChanged="CheckChangedMethod">
and added a corresponding method to the WebPage class in WebPage.aspx.cs:
protected void CheckChangedMethod( object sender, TreeNodeEventArgs e )
{
StatusLabel.Text = "A checkbox was changed!";
}
When I launch the page, though, I get an error screen that says:
CS1061: 'ASP.webpage_aspx' does not contain a definition for 'CheckChangedMethod' and no extension method 'CheckChangedMethod' accepting a first argument of type 'ASP.webpage_aspx' could be found (are you missing a using directive or an assembly reference?)
I have found that if I move the method to within a tag on WebPage.aspx, it works! Unfortunately, though, I need the method to access classes and methods in other parts of the site, which I can't from within the script tag (...right?). How can I get my event handler recognized by the compiler without removing it from the WebPage class?
Edit:
The total markup looks like this:
<%# Page Title="Web Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireUp="true" CodeBehind="WebPage.aspx.cs" Inherits="Project.WebPage" %>
<%# MasterType VirtualPath="~/Site.Master" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolKit" %>
<asp:Content ID="Content1" ContentPlaceHolder="HeadContent" runat="server">
<!-- This is where I placed the script tag to test the method -->
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolder="MainContent" runat="server">
<asp:ScriptManager ID="ScriptManager" runat="server"></asp:ScriptManager>
<h2><em>Headline</em></h2>
<br />
<asp:TreeView ID="SimpleTreeView" runat="server" ExpandDepth="0" ShowCheckBoxes="All">
</asp:TreeView>
<asp:Label ID="StatusLabel" runat="server">No change yet.</asp:Label>
<asp:Button ID="SaveButton" runat="server" Text="Save Changes" PostBackUrl="~/WebPage.aspx" />
</asp:Content>
Well... Not sure what happened, but after fixing bugs elsewhere on our site, the code above magically decided to start working. I'm not going to question it.

add content to site.master control

I have a master page file and I have always added additional style sheets pragmatically using Page.Header.Controls.Add etc. But we have a client that wants the css files in a specific place, so I noticed that in the head section there is a
<asp:ContentPlaceHolder ID="HeadContent" runat="server">
so I thought I could just add it into there.
I have tried
ContentPlaceHolder blar = (ContentPlaceHolder)Master.FindControl("HeadContent");
blar.Controls.Add(css);
But nothing appears, can anyone help?
U can add your css file like that;
ContentPlaceHolder blar = (ContentPlaceHolder)Master.FindControl("HeadContent");
HtmlLink css= new HtmlLink();
css.Attributes.Add("rel", "stylesheet");
css.Attributes.Add("type", "text/css");
css.Href = "/Styles/site.css";
blar.Controls.Add(css);
Check out the answer to this question: https://stackoverflow.com/a/2969360/1372321
It seems to do what you want :)
Update
To add content at a specific place in the header, and you are using .Net 4.5, you can use the System.Web.Optimatization API and bundle the styles. Then in your head, you can use the provided control:
<webopt:BundleReference runat="server" Path="~/Content/css" />
You can see an example of this in the default WebForms project template.
If you're using an older version of .Net, you can use content placeholder in your master page, and then add controls to that specific placeholder like so:
In master page head
<asp:ContentPlaceHolder runat="server" ID="HeadContent" />
In aspx page
<asp:Content runat="server" ContentPlaceHolderID="HeadContent">
<asp:PlaceHolder runat="server" ID="placeHolderHead"></asp:PlaceHolder>
</asp:Content>
Then you can simply add the Link controls to the placeholder programatically.

Null Reference Literal Control

I am trying to pass text to a Literal, the parent.master has the ContentTemplateID's and the Child.master has the contentID's, one of them is the literal of form
<asp:Literal runat="server" ID="myLiteral"></Literal>
I am trying to pass it from a UserControl.cs file like this
gooleTrackin = track.GetTrack(track.OrderType.YAHOO);
Literal mpLiteral = (Literal)this.Parent.Page.Master.FindControl("myLiteral");
mpLiteral.Text = gooleTrackin.ToString(); //nullReference here
But it is giving me NulLReference in the last line.
By the way I do not have access to the .cs files of the master pages, it has to be done through the UserControl.
Thank you
ADDITIONAL CODE (THIS IS LOCATED IN THE CHILD.MASTER)
<%# Master Language="C#" AutoEventWireup="true" MasterPageFile="../common/child.master" %>
<%# Register Src="UserControl.ascx" TagName="UserControl" TagPrefix="uc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server">
<div class="inner"><uc1:UserControl ID="theRceipt" runat="server" Visible="true"/>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="BottomContentTemplate" Runat="Server">
<div style="margin-bottom:30px;">
<asp:Literal ID="myLiteral" runat="server"></asp:Literal>
Back to Home Page
</div>
</asp:Content>
When master page is used, controls from master page are merged into the control hierarchy of page so this can be an issue while finding controls. I will suggest that you try following and see if it works:
Literal mpLiteral = (Literal)this.Page.FindControl("myLiteral");
OR
Literal mpLiteral = (Literal)this.Parent.FindControl("myLiteral");
Otherwise, you may have to try recursive find - see http://www.west-wind.com/weblog/posts/2006/Apr/09/ASPNET-20-MasterPages-and-FindControl
However, I will rather recommend a alternate way - assuming that you have defined your literal control in Child.Master and Child is the name of code behind class for master, you can add an helper method in it such as
public void UpdateMyLiteral(string text)
{
myLiteral.Text = text;
}
And in user control code, invoke the helper method such as
((Child)this.Page.Master).UpdateMyLiteral("xyz");
Note that we are casting master to its code-behind class.

Categories