Rendering of asp.net controls - asp.net

I find it hard when using asp.net controls, to make proper css files because I don't know what the html output for the different controls end up as.
For example, if I want to add a div tag using a asp.net control, it's not easy to know what kind of control I can use.
Are there any documentation that shows for each asp.net control, what the rendered html for that control will be? I understand that some controls will probably change it's output due to how it's configured, but most controls will at least follow a pattern here.
The best would of course be a service on the web where you can put in the asp.net control definition and get the rendered html out.
Currently I have to put a control into my webform, run it and check the source in the browser, and if it's not the correct html tag, try another control and repeat. That get's tedious quite fast.

If you want to know to what html-controls a server-control is rendered, you could call RenderControl:
Dim myGridView as new GridView
Dim sb as New StringBuilder()
Dim sw as New IO.StringWriter(sb)
Dim textWriter as New HtmlTextWriter(sw)
myGridView.RenderControl(textWriter)
' now we can have a look what asp.net has rendered: '
Dim gridViewHTML as String = sb.ToString()
The rendered html will even differ from browser to browser for example when ASP.Net thinks the client uses a "lower"-browser(BrowserCaps), a Panel will be rendered as Table instead of a DIV.
By the way, if you're testing my above code on controls inside of your page, you have to override VerifyRenderingInServerForm otherwise you get a "...must be placed inside a form tag with runat=server"-error:
Public Overrides Sub VerifyRenderingInServerForm(ByVal control As System.Web.UI.Control)
Return
End Sub

I would recommend adding a CssClass to your WebControls, and doing all your styling using classes, rather than HTML element types. As Tim Schmelter says, the html can render differently for different clients (I seem to remember a Panel can be a span as well under certain circumstances).
To avoid actually having to add the CssClass each time, you can subclass the WebControl you want, then set it's CssClass in Control_Init.

Related

Passing Angular data to code-behind function on button click

I have a code-behind function that is called when a hyperlink is clicked. The function should then get the name attribute from the hyperlink and use that string to call another function. The name attribute is being populated by an angular ngRepeat. My problem is that when I try to get the name attribute in the code-behind, it just shows an empty string and not the name attribute that "should" have been passed.
HTML
Print Invoice
Final HTML Output
<a data-name="90979157" href="javascript:__doPostBack('ctl00$MainContentPlaceholder$ctl00','')">Print Invoice</a>
VB Code-Behind
Public Sub btnPrintInvoiceClicked(ByVal sender As Object, ByVal e As EventArgs)
Dim inv As HtmlAnchor = CType(sender, HtmlAnchor)
Dim invoiceNumber As String = inv.Name
GetInvoicePDF(invoiceNumber)
End Sub
Thanks in advance!
Edit: Added HTML output
As you can see from the HTML that gets sent to the browser, .NET causes the <a> tag to perform the javascript function __doPostBack('ctl00$MainContentPlaceholder$ctl00','') when it is clicked. This function submits the <form> tag which surrounds the entire contents of your page back to your code-behind class. That code-behind then does special magic with the hidden form elements on your page that .NET webforms put there to identify the state of the page.
This is the classic .NET webforms paradigm, and is a lot more complex than the <a> tag pointing to a url would have you believe. It is also very different from how angularjs is meant to be used. You said in a comment that the data-name value is correctly passed when hard-coded in. This is probably the doing of the __doPostBack function, and it's unsurprising that it does not play well with angular (since its generated per page by code that was written before angular was created). You have two possible options:
Change your <a> tag to an <input type="button" value="{{invoice.DocumentNumber}}" runat="server" ID="yourButton" /> Why would this work? Simply put, you just want angular to transclude the right value into the html so that when webforms submits, the data is passed to your page. Since <a> tags have no relationship to form values, the page rightly ignores its data-name value. In fact I'm surprised that hardcoding the value works at all, because a form post should ignore things that are not form elements. It cannot ignore an <input> element, though.
Change your Public Sub btnPrintInvoiceClicked... method from being a server-side onclick handler to be its own endpoint. Take a look at http://www.asp.net/web-api or its older, web-forms-era cousin: http://www.codeproject.com/Articles/353260/ASP-NET-Advanced-Generic-Handler-ASHX
As an aside, this is the first time I've heard of someone trying to use angular with webforms, the latter being a bit of a dinosaur that Microsoft has hinted at abandoning and the former being in-vogue javascript MVC darling. I know it may not be possible, but you should consider moving to .NET MVC if possible since it is a much better backend environment in which to host your angularjs app.

Header.Stylesheet.CreateStyleRule on partial postback

I've recently added an UpdatePanel to a single webpage which renders different usercontrols on button clicks. I'm struggling with a problem where i'm adding inline styling into the header dynamically with Header.Stylesheet.CreateStyleRule - the problem is that it doesn't get inserted on partial postbacks and it does make sense. This is obviously because it's a partial postback and the header is only being rendered when the page loads the first time.
The styling is being added by the following methods, which gets the styling from a database:
Private Sub InitializeStylesheet(ByVal ButtonId As Integer)
Dim CSSStylesheet As Stylesheet = StyleBackend.GetStylesheets(ButtonId)
Dim IdClassList As List(Of StyleIDClass) = StyleBackend.GetStylesheetsStyleIDClass(CSSStylesheet.StylesheetID)
'Iterates through the cssidclass
For Each cssidClass In IdClassList
Dim styleItems As List(Of StyleItem) = StyleBackend.GetStyleItemsByIDorClass(cssidClass.StyleIDClassID)
Dim cssString As String = Nothing
For Each StyleItem As StyleItem In styleItems
cssString += StyleItem.Property & ":" & StyleItem.Value & ";"
Next
'Iterates all cssitems which belongs to a cssidclass
Me.Header.StyleSheet.CreateStyleRule(New CustomStyle(cssString), Nothing, cssidClass.ClassOrID)
Me.Header.ViewStateMode = UI.ViewStateMode.Disabled
Next
End Sub
I've been googling my ass off trying to get this to work, but it seems to be impossible.
This msdn article literal says that it is impossible to do what i'm trying to do.
http://msdn.microsoft.com/en-us/library/system.web.ui.htmlcontrols.htmlhead.stylesheet.aspx
Adding styles or style rules programmatically during asynchronous postbacks is not supported. When you add AJAX capabilities to an ASP.NET Web page, asynchronous postbacks update regions of the page without updating the whole page. For more information, see Microsoft Ajax Overview.
Does anyone have a suggestion or alternative way of doing this?
Thank you!
One solution is just to include the styles in your main stylesheet(s) rather than modifying them dynamically. Even if they are data-driven, you could output them with the main page via an HTTP handler if the total list isn't too large.
Alternatively (and probably more efficiently), you can return the style data to the client as a string and process it there.
You can listen for the EndRequest event on the client script manager:
function endRequest(){
// look at the updated DOM
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
Perhaps the following sequence:
Initiate async postback
Render the styles to a hidden field inside the UpdatePanel
On endRequest, examine the DOM to see if it contains a hidden field with styles (based on naming convention, data attributes, or just ID)
Grab the values out of the hidden field and add them to the page's style rules using JavaScript

Finding an ascx control inside aspx

I'm finding a dropdown in an ascxcontrol on my aspx in the following way.
Dim cp As ContentPlaceHolder = DirectCast(Page.Form.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)
Dim ascx As UserControl = DirectCast(cp.FindControl("drpType"), UserControl)
Dim drpType As DropDownList = DirectCast(ascx.FindControl("drpType"), DropDownList)
Is there a faster way without having to acces all the elements on the page?
I wouldn't try and reference a control within a user control this way, the user control should encapsulate these and the page should talk to public properties.
Depends on what you're trying to do.
Without a great deal of context, I can only assume that you are either getting or setting the value of the dropdown.
I wouldn't use the approach that you're going for. It introduces an element of implementation specific coupling.
You would be far better off exposing whatever you need to get/set via a property which you can call from the .aspx page.
However, in answer to your question, if you are going to reference the dropdown from the .aspx page, you will have to use FindControl.
If you know what naming containing the control is in you can go
ucNamingContainerControl.FindControl(controlId)
That will at least limit it to that section of the page.
Otherwise the only other thing I can think of is if you are accessing a predefined set of controls - put them in a Dictionary collection and use the Find method to pick them out. Could be a quicker retrieval but might look a bit clunky on the page.

How to change html view of web user control

I am creating a web user control for a simple poll. I am currently registering it on the page and then referencing it via tagprefix.
The form for the poll is in basic html (no server controls) and is in the front-end of the web control. How can I change the look of the user control depending on the settings passed into it? Is this possible without using server controls?
Update
Can I change the html layout of a user control? If so could someone post some examples. Please note I do not use asp.net form controls, so none of that please :)
You might be able to also use jQuery to replace existing css setting in your code. Create properties on for your user control, and then pass settings in the classes. Then use jQuery to replace them. This however requires jQuery to be linked to your page (or within your control) and you'd have to write the CSS classes out to the jQuery code (using server controls, but you could use the literal control so there's no excess code).
Personally I'd go with the option of using server controls instead of straight up HTML, you'd get alot more flexibility, and then passing through the settings would be pretty straightforward, put something like this in your controls backend code:
Private _TextBoxCssClass As String
Public Property TextBoxCssClass() As String
Get
Return _TextBoxCssClass
End Get
Set(ByVal value As String)
_TextBoxCssClass = value
txtBox1.CssClass = value
txtBox2.CssClass = value
End Set
End Property
You most likely want to have a property or event in the control that changes the css. It may end up best to add some server controls or javascript / jquery to make it easier.
If its only the styles you want to change, then you can expose a property to set the style attribuites of the respective control inside your User Control. If you want to control the whole HTML layout of the control then Custom Control is the viable option.

Page.ParseControl to find HTMLImage

I have a richtext textbox on a webpage that will be used to create email templates. This textbox returns HTML as a string. I need to get the source of all the images from the HTML so that the images can be stored in the database. Once the HTML is returned the images have already been loaded to the server and the new path has been used as the source of the image.
I would like to parse the controls, loop through the controls as seen below, find the images save to the database and change the source to a new value.
However when the string is parsed, it always returns one literal control unless there is a runat server attribute assigned to the tag. If the run at server is present it correctly identifies the control as an HTMLImage control.
Is there away to get the page to parse all the controls regardless of if they are server controls?
Dim s As String = "<P><IMG src=""http://localhost/MessageImages/14699666.jpg""></P>"
Dim cnts As Control = Page.ParseControl(s)
For Each c As Control In cnts.Controls
If TypeOf c Is System.Web.UI.HtmlControls.HtmlImage Then
Dim src As String = CType(c, HtmlImage).Src
'TODO: Save image to database
'TODO: Change source
End If
Next
It sounds to me like you'd be better of using something like the HTML Agility Pack to parse the raw HTML from the editor instead. As it works with the pure HTML you don't need to worry about whether controls are server controls or HTML controls etc.

Resources