I've got the following asp.net code that generates a listitem dynamically and populates it with a panel that contains a gridview:
Panel panBlocks = new Panel();
panBlocks.ID = "PanBlockQuestionID" + recordcount.ToString();
panBlocks.Width = 1300;
panBlocks.Height = 100;
panBlocks.BackColor = System.Drawing.ColorTranslator.FromHtml("#fabb3d");
GridView gvEmployee = new GridView();
gvEmployee.ID = "gvEmployees" + recordcount.ToString();
gvEmployee.AutoGenerateColumns = true;
gvEmployee.DataSource = dtBlocks;
gvEmployee.DataBind();
gvEmployee.Style.Add("position", "relative");
panBlocks.Controls.Add(gvEmployee);
It generates the gridview but wraps it in a div. How do I stop it generating the div as it messes up the styling. The html it generates is:
<li id="CPH_Body_liQuestions3" class="liQuestions" style="height:40px;" myCustomIDAtribute="3"><a></a><input type="image" name="ctl00$CPH_Body$lblImg3" id="CPH_Body_lblImg3" class="liQuestionsLabel2" src="../../Images/gtk_cancel.png" style="width:30px;" /><input type="image" name="ctl00$CPH_Body$lblImg3" id="CPH_Body_lblImg3" class="liQuestionsLabel2" src="../../Images/phone_book_edit.png" style="width:30px;" /><span id="CPH_Body_lblID3" class="liQuestionsLabel" style="display:inline-block;width:35px;">298,</span><span id="CPH_Body_lblQuestionType3" class="liQuestionsLabel" style="display:inline-block;width:25px;">1, </span><span id="CPH_Body_lblMsgPrompt3" class="liQuestionsLabel" style="display:inline-block;width:300px;">Fit nylon spacer BG502 to tray,</span><span id="CPH_Body_lblExpectedResp3" class="liQuestionsLabel" style="display:inline-block;width:100px;">YES,</span><span id="CPH_Body_lblImg3" class="liQuestionsLabel" style="display:inline-block;width:30px;"> img: </span><span id="CPH_Body_lblFailMsg3" class="liQuestionsLabel" style="display:inline-block;width:300px;">Not fitted,</span><span id="CPH_Body_lblRetryMsg3" class="liQuestionsLabel" style="display:inline-block;width:300px;">Retry,</span><span id="CPH_Body_lblStart3" class="liQuestionsLabel" style="display:inline-block;width:10px;">,</span><span id="CPH_Body_lblEnd3" class="liQuestionsLabel" style="display:inline-block;width:10px;">,</span><img id="CPH_Body_lblImg3" class="liQuestionsLabel2" onclick="showPanel('CPH_Body_liQuestions3')" src="../../Images/block3.png" style="width:30px;" /><div id="CPH_Body_PanBlockQuestionID3" style="background-color:#FABB3D;height:100px;width:1300px;">
<div>
<table cellspacing="0" rules="all" border="1" id="gvEmployees3" style="border-collapse:collapse;position:relative;">
<tr>
<th scope="col">B1ID</th><th scope="col">B1IncEx</th><th scope="col">B1Criteria</th>
</tr><tr>
<td>3</td><td>EX</td><td>590P</td>
</tr>
</table>
</div>
</div></li>
How do I stop the div being generates please as I can't apply styling to it.
Many Thanks
Use a PlaceHolder instead of a Panel, the difference is that the PlaceHolder is not rendered as a div whereas a Panel always.
The PlaceHolder control does not produce any visible output and is used only as a container for other controls on the Web page.
While I haven't found a way to remove the DIV completely, it is possible to change it so that the DIV no longer wraps the TABLE if you're in a position where you can define and use your own custom GridView control.
The trick is to prematurely close the opening DIV tag, so the TABLE follows it in the HTML, rather than being inside it. If needed, you can also add attributes to the DIV, such as a class name, to ensure that it does not affect the surrounding HTML.
using System.Web.UI;
public class MyGridView
: System.Web.UI.WebControls.GridView
{
public MyGridView()
{
}
public override void RenderControl(HtmlTextWriter writer)
{
/* The underlying GridView class renders a DIV as a container in
RenderControl(), so we can add attributes here, such as a class
to hide it.
*/
writer.AddAttribute(HtmlTextWriterAttribute.Class, "hidden");
base.RenderControl(writer);
}
protected override void RenderContents(HtmlTextWriter writer)
{
/* We don't want the underlying GridView's container DIV to actually
wrap the internal TABLE, so calling RenderEndTag() here will cause
it to be closed before the TABLE is rendered (which happens in
RenderChildren())...
*/
writer.RenderEndTag();
base.RenderContents(writer);
/* ...However, when this function exits, RenderControl() will call
RenderEndTag() itself to close what is expected to be the container
DIV, so we need to provide a open tag for it. We'll use a SPAN as
that will have the least effect on the HTML and we could, of
course, add any required attributes to style it, etc, if required.
*/
writer.RenderBeginTag(HtmlTextWriterTag.Span);
}
/* If you need to add any additional attributes to the TABLE tag, you
can do that here with a call to writer.AddAttribute(); if not, this
override is redundant.
protected override void RenderChildren(HtmlTextWriter writer)
{
// TODO: call writer.AddAttribute() if required
base.RenderChildren(writer);
}
*/
}
HACK ALERT!
Clearly, this is implementation-specific and subject to change with new versions of ASP.NET. However, in most cases, an upgrade to the ASP.NET version would most likely require testing/review anyway, so it shouldn't be too much of an issue.
Related
I have a Blazor Server app. I dynamically add a custom control (which I created in a Razor Class Library) to my page, like this:
<div class="container ">
<div class="row ">
<div class="col-12">
<label>#p_section.question</label>
</div>
</div>
#foreach (object new_control_model in p_section.list_of_control_models)
{
DisaggregateControlModel new_disag_model = (DisaggregateControlModel)new_control_model;
<DisaggregateControl #ref="myComponents[new_disag_model.id]" model="new_disag_model">
</DisaggregateControl>
}
</div>
This add the control to my dictionary, which I can access.
#code {
private Dictionary<string, object> myComponents = new Dictionary<string, object>();
}
In the custom control, I have a method that sets a bool, which allows me to display or hide a Div. In the web component that has this code, I want to iterate over all the objects in myComponents and either turn on or off the div display. I do that like this:
foreach (string id in some_list_of_ids){
//find the object in myComponents list
object found_obj = myComponents.FirstOrDefault(x => x.Key == id).Value;
//cast to my custom control
DisaggregateControl myControl = (DisaggregateControl)found_obj;
// based on property, determine if I should show the div or not
if(myControl.some_vale >0){
//show
myControl.showDiv(true);
}else{
myControl.showDiv(false);
}
}
//updated all the controls, so update the page
StateHasChanged();
If I debug and walk through, I can see that the code works. The correct divs are shown/hidden. Until the code reaches StateHasChanged(), and then all the divs are hidden. If I remove StateHasChanged then the code also does not work (the divs are not shown, when they should be).
I am not sure what the issue is or how to best handle this?
Turns out that it was an issue with my variable. In the custom library, I showed/hid the div by setting a bool value. But, I inadvertently made the bool static. Once I changed that, it worked fine. I assume because the variable was static, once I changed it for one control, it got changed for all controls.
Suppose I have this markup:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<a runat="server" id="myLink" href="<%# Container.DataItem %>">Here</a>
</ItemTemplate>
</asp:Repeater>
In the code-behind, I can find out that <a> is converted to HtmlAnchor:
private void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
HtmlAnchor myLink = (HtmlAnchor)Repeater1.FindControl("myLink");
}
But how does the compiler know that <a> is HtmlAnchor? Is it hard-coded in the compiler?
If I write
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<Foo href="<%# Container.DataItem %>">Here</a>
</ItemTemplate>
</asp:Repeater>
and want the <Foo> tag to be converted to my HtmlFoo class, how do I achieve that?
I just want to have a deeper understanding of the compilation process behind the scenes.
You can learn a lot about the internals of ASP.NET by delving into the Reference Source.
It turns out that the mapping from unprefixed HTML tags to HtmlControl subclasses is hard-coded in an internal class called HtmlTagNameToTypeMapper:
static Hashtable _tagMap;
Type ITagNameToTypeMapper.GetControlType(string tagName, IDictionary attributeBag) {
Type controlType;
if (_tagMap == null) {
Hashtable t = new Hashtable(10, StringComparer.OrdinalIgnoreCase);
t.Add("a", typeof(HtmlAnchor));
t.Add("button", typeof(HtmlButton));
t.Add("form", typeof(HtmlForm));
// [and much more...]
_tagMap = t;
}
// [...]
}
GetControlType is called by another internal class called MainTagNameToTypeMapper:
int colonIndex = tagName.IndexOf(':');
if (colonIndex >= 0) {
// [...]
}
else {
// There is no prefix.
// Try the Html mapper if allowed
if (fAllowHtmlTags) {
return _htmlMapper.GetControlType(tagName, attribs);
}
}
There's no public API to register more unprefixed HTML control types.
On a more localized scale, it is possible for a parent control to customize how the tag names of its child controls are interpreted. To do this, derive from ControlBuilder, override GetChildControlType, and decorate the parent control class with the [ControlBuilder(typeof(...)] attribute.
When you add runat="server" to a control in ASP.NET, a corresponding variable of type HtmlControl (or some subclass thereof) is automatically added to your page (in the designer file). That way you can access that control as a variable. For most common HTML controls, there are subclasses of HtmlControl (such as HtmlAnchor for anchor/link tags). Other controls (such as <div>) get the HtmlGenericControl type. For those, you specify the tag (div) as a property. So your Foo tag would get like a div: a variable of type HtmlGenericControl with a tag of "Foo".
Edit: this is for standard HTML elements. If you create an ASP control (such as <asp:TextBox...>, then the resulting variable will be a subclass or WebControl instead of HtmlControl.
I am listing my data in an ItemTemplate.Then inside the ItemTemplate, i have two div tags as follows:
<ItemTemplate>
<div id="contentdiv">
<h4 id="titleresult"><%# Server.HtmlEncode(Eval("Name").ToString())%></h4>
</div>
<div id="showclick" class=hideAll>
<p class="brief"><%# Server.HtmlEncode(Eval("LegalName").ToString())%></p>
<p class="brief"><%# Server.HtmlEncode(Eval("FirstName").ToString())%></p>
<p><%# Server.HtmlEncode(Eval("LastName").ToString())%></p>
</div>
</ItemTemplate>
Then i have the css to define the hideAll class so that when the page loads, the data in this div tag is hidden until the user clicks on the contentdiv link.
.hideAll { display:none }
.displayAll { display:block; top:0px}
Then finally i have the javascript part for firing the click event.
<script type="text/javascript">
function showResults(UserID) {
var contentdiv= document.getElementById('contentdiv');
var showclick = document.getElementById('showclick');
<%
long id =0;
DataAccess dataAccess = new DataAccess();
Data = dataAccess.GetCounterParty(id);
%>
var UserID = <%=dataAccess.GetCounterParty(id) %>
contentdiv.style.visibility = "visible";
$(showclick).removeClass('hideAll');
}
</script>
The UserID is the id of every element in the list. The problem is, the click affects only the first element no matter which other element i click on the list.
In html id is used to refer to one element.
If you use it multiple times the browser would default to the first element.
You should use a class selector. Something like:
$(".contentdiv").click(function(){
$(this).next().removeClass('hideAll');
});
Here is a working example. I used toggleClass though, it seems more appropriate to me.
An id is a unique identifier, you cannot have two or more things on the same page with the same identifier and expect things to work properly. Make your identifiers unique, and bind to the click event using a class selector instead.
you should use class instead of id, id are unique, which only exist in 1 page, class can exist in multple div
some idea for u
html
<div class="showclick hideAll">
script
$('.showclick').on('click', function(){
$(this).toggle(); //toggle to show or hide, can be any element u want to toggle instead of this
});
I'm currently working with a listview in which I want an htmltablecell to possess the onclick property which is driven by the codebehind rather than a javascript.. However I'm guessing that's pretty much a dream getting it to obey the C# code... Anyways this is what I want it to run:
protected void show_anm(object sender, EventArgs e)
{
Label hiddenc = (Label)listview1.FindControl("hidden");
Alert.Show(hiddenc.Text);
}
and here's the Alert class
public static class Alert
{
public static void Show(string message)
{
string cleanMessage = message.Replace("'", "\\'");
string script = "<script type=\"text/javascript\">alert('" + cleanMessage + "');</script>";
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null && !page.ClientScript.IsClientScriptBlockRegistered("alert"))
{
page.ClientScript.RegisterClientScriptBlock(typeof(Alert), "alert", script);
}
}
}
The point is creating a listview with a two conditional tablecells, one which appears only when a certain condition is met and the other appears every other time (that's alredy sorted out). Where the one demanding a condition is Clickable, and upon clicking it it'll display an Alertbox with Data from a specific DB cell...
Sorry if my language and the question seemes off, English isn't my native language and I haven't doused myself in Coffe yet.
Any help on the matter would be most appritiated
EDIT1*
<asp:Listview ................
<ItemTemplate>
<tr ......>
<td id=default .....>
<asp:label ........ Text='<%# eval("stuff") %> />
</td>
<td id=conditional onclick=alert()..........>
<asp:label ......... Text='<%# eval("stuff") %> />
</td>
<td id=hidden visible=false ...........>
<asp:label ......... Text='<%#eval("stuff i want in alert") %>' />
.....
<script tyupe="text/javascript">
function alert()
{
var msg = document.getElementById("tried with label id and tablecell id nothing seemingly worked").value;
alert(msg);
}
</script>
I recently made a workaround that shows the data I want to display in the labels tooltip but I'd still prefer the alertbox to work properly as it feels more natural to click something.
Edit2 In case anyone is wondering I used the ItemDataBound event to bind the visibility of cells default and conditional within an if clause to make sure the control exists and the conditions are met.
I am confused as to why you're doing what you're doing. Why do you want the codebehind to handle an onclick event of a htmltablecell when you are pumping out javascript to show an alert anyway?
Why not just handle the whole logic within Javascript?
A postback from a htmltablcell will also require javascript
Set your tablecell to call a javascript function which would obtain the alert text from the hidden value and display that;
function ShowAlert()
{
var message = document.getElementbyId("hidden").value;
alert.show(message);
}
I am writing a bit of code to add a link tag to the head tag in the code behind... i.e.
HtmlGenericControl css = new HtmlGenericControl("link");
css.Attributes["rel"] = "Stylesheet";
css.Attributes["type"] = "text/css";
css.Attributes["href"] = String.Format("/Assets/CSS/{0}", cssFile);
to try and achieve something like...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css" />
I am using the HtmlGenericControl to achieve this... the issue I am having is that the control ultimatly gets rendered as...
<link rel="Stylesheet" type="text/css" href="/CSS/Blah.css"></link>
I cant seem to find what I am missing to not render the additional </link>, I assumed it should be a property on the object.
Am I missing something or is this just not possible with this control?
I think you'd have to derive from HtmlGenericControl, and override the Render method.
You'll then be able to write out the "/>" yourself (or you can use HtmlTextWriter's SelfClosingTagEnd constant).
Edit: Here's an example (in VB)
While trying to write a workaround for umbraco.library:RegisterStyleSheetFile(string key, string url) I ended up with the same question as the OP and found the following.
According to the specs, the link tag is a void element. It cannot have any content, but can be self closing. The W3C validator did not validate <link></link> as correct html5.
Apparently
HtmlGenericControl css = new HtmlGenericControl("link");
is rendered by default as <link></link>. Using the specific control for the link tag solved my problem:
HtmlLink css = new HtmlLink();
It produces the mark-up <link/> which was validated as correct xhtml and html5.
In addition to link, System.Web.UI.HtmlControls contains classes for other void element controls, such as img, input and meta.
Alternatively you can use Page.ParseControl(string), which gives you a control with the same contents as the string you pass.
I'm actually doing this exact same thing in my current project. Of course it requires a reference to the current page, (the handler), but that shouldn't pose any problems.
The only caveat in this method, as I see it, is that you don't get any "OO"-approach for creating your control (eg. control.Attributes.Add("href", theValue") etc.)
I just created a solution for this, based on Ragaraths comments in another forum:
http://forums.asp.net/p/1537143/3737667.aspx
Override the HtmlGenericControl with this
protected override void Render(HtmlTextWriter writer)
{
if (this.Controls.Count > 0)
base.Render(writer); // render in normal way
else
{
writer.Write(HtmlTextWriter.TagLeftChar + this.TagName); // render opening tag
Attributes.Render(writer); // Add the attributes.
writer.Write(HtmlTextWriter.SelfClosingTagEnd); // render closing tag
}
writer.Write(Environment.NewLine); // make it one per line
}
The slightly hacky way.
Put the control inside a PlaceHolder element.
In the code behind hijack the render method of the PlaceHolder.
Render the PlaceHolders content exactly as you wish.
This is page / control specific and does not require any overrides. So it has minimal impact on the rest of your system.
<asp:PlaceHolder ID="myPlaceHolder" runat="server">
<hr id="someElement" runat="server" />
</asp:PlaceHolder>
protected void Page_Init(object sender, EventArgs e)
{
myPlaceHolder.SetRenderMethodDelegate(ClosingRenderMethod);
}
protected void ClosingRenderMethod(HtmlTextWriter output, Control container)
{
var voidTags = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase) { "br", "hr", "link", "img" };
foreach (Control child in container.Controls)
{
var generic = child as HtmlGenericControl;
if (generic != null && voidTags.Contains(generic.TagName))
{
output.WriteBeginTag(generic.TagName);
output.WriteAttribute("id", generic.ClientID);
generic.Attributes.Render(output);
output.Write(HtmlTextWriter.SelfClosingTagEnd);
}
else
{
child.RenderControl(output);
}
}
}