Databound Controls With Null Value Being Rendered?
Feb 28, 2011
Although I'm a huge fan of Databound controls since ASP.Net 2.0 and have been using them a lot since learning them, I seem to have stumbled upon an unnoticed(or rather not cared about) issue that these controls seem to have.
I'm using ASP.Net 3.5 and the issue that I noticed is that when using Databound controls(such as Labels, HyperLinks) inside a Data-Control(such as Datalist, Gridview etc.), even if the value returned for one column is NULL, it is still rendered albeit as an empty tag.
For eg: I have a Datalist in which I have a Label whose value may or may not be NULL. Now there's no problem when the value is not NULL, the problem is when the value is NULL. Ideally, no HTML should be rendered for a controls that don't have any value, but in this case, the HTML(<span></span> in case of the Label) of the corresponding NULL valued control is still being rendered.
Now, as I said earlier that most people won't care about this as it isn't much of an issue, but if you consider the fact that this control may be enclosed in a hierarchy of parent controls, and then repeated many a times, this could significantly increase the HTML content(since the ID of your HTML content is based on the parent controls) without any Text added to maintain the Text/HTML ratio, thereby becoming a cause for the Search Engines to shy away from indexing your pages fully.
I couldn't find anything related to this matter anywhere else so I thought to bring it up here. Is this really an issue with databound controls or am I missing something here?
So I finally managed to create a control which basically shows a bunch of Panels with an extra property. I use it like this:
[Code]....
This renders fine and shows the text in the TabPanel controls. However, when I replace the plain text with something a little more exciting, say an UpdatePanel so it looks like this:
[Code]....
Then I get this weird error:
Page cannot be null. ensure that this operation is being performed in the context of an ASP.NET request.[InvalidOperationException: Page cannot be null. ensure that this operation is being performed in the context of an ASP.NET request.] System.Web.UI.UpdatePanel.get_IPage() +647672 System.Web.UI.UpdatePanel.Render(HtmlTextWriter writer) +20 SP.adminonly_reports_loginreport_aspx.__RenderTabPanel1(HtmlTextWriter __w, Control parameterContainer) in D:....eport.aspx:37 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +115 System.Web.UI.WebControls.WebControl.RenderContents(HtmlTextWriter writer) +13 System.Web.UI.WebControls.WebControl.Render(HtmlTextWriter writer) +42 TabPanels.TabPanelHolder.Render(HtmlTextWriter w) in D:e4Webwwwrootlms_workingTabPanelsTabPanelsTabPanelHolder.vb:146 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +240 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +240 System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) +253 System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output) +87 System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) +53 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +240 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +240 System.Web.UI.Page.Render(HtmlTextWriter writer) +38 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4240
If I take out the UpdatePanel and replace it with an ASCX control I made that simply puts database data into some DropDownLists, like this...
[Code]....
Then the page loads, but the data is not loaded into CustomerUserList1, and the dropdownlists within it are all blank. CustomerUserList1 has worked fine for years when used directly in a normal Panel/Page UpdatePanel.
I wanted to get the total row count in a GridView's databound event handler, so I tried the following:
protected void grid_DataBound(object sender, EventArgs e) { GridView grid = (GridView)sender; DataSet data = grid.DataSource as DataSet; if (data == null) return; int totalRows = data.Tables[0].Rows.Count; }
The problem is that the grid.DataSource property is null. The DataSourceID property is not null, so does that mean that I can't access the DataSource object in the DataBound event handler unless I assign the DataSource property directly?
Edit1: Here is the code in my GridHelper class for adding rowcount to the BottomPagerRow. I would like to get rid of the requirement to pass in the ObjectDataSource, but can't because I need to use the Selected event to get total row count. Hence the reason for the question. I also think this might be better in a custom control where I can access ViewState, and/or create child controls during the Init event (I still have a problem to resolve with the way the pager renders with an extra cell), but then I'd still have the problem of how to get to the total row count when the DataSource itself doesn't appear to be available in any GridView events.
Edit 2: Not really relevant to the specific problem, but I resolved the problem I was having with the pager rendering so i've updated the code posted. I found the trick here: [URL]
#region Fields private int totalRows = -1; #endregion #region Constructors /// <summary> /// Initializes a new instance of the <see cref="GridHelper"/> class. /// Adds EventHandlers to the GridView to display results from the ObjectDataSource in the footer. /// Marked as obsolete because AddResultsToFooter method provides a static access to the same functionality /// An instance of GridHelper is required by the passed in GridView to store the totalRows value between the two event handlers /// </summary> /// <param name="grid">The grid.</param> /// <param name="source">The ObjectDataSource linked to the GridView.</param> [Obsolete("Use AddResultsToFooter instead.")] [EditorBrowsable(EditorBrowsableState.Never)] public GridHelper(GridView grid, ObjectDataSource source) { source.Selected += source_Selected; grid.PreRender += grid_PreRender; } #endregion #region Event Handlers private void grid_PreRender(object sender, EventArgs e) { GridView grid = (GridView)sender; if (grid.HeaderRow != null) grid.HeaderRow.TableSection = TableRowSection.TableHeader; //Add a cell to the bottom pager row to display the total results if (grid.BottomPagerRow == null || !grid.BottomPagerRow.Visible) return; //Get the control used to render the pager //http://michaelmerrell.com/2010/01/dynamically-modifying-the-asp-net-gridview-paging-control/ Table tblPager = grid.BottomPagerRow.Cells[0].Controls[0] as Table; if (tblPager == null) return; if (totalRows < 0) { //The DataSource has not been refreshed so get totalRows from round trip to client addResultsToPagerTable(tblPager, grid.Attributes["results"]); return; } int firstRow = grid.PageIndex * grid.PageSize + 1; int lastRow = firstRow + grid.Rows.Count - 1; string results; if (totalRows <= grid.PageSize) results = string.Format("<span class='grid-pager'>{0} Results</span>", totalRows); else results = string.Format("Results <b>{0}</b> to <b>{1}</b> of <b>{2}</b>", firstRow, lastRow, totalRows); addResultsToPagerTable(tblPager, results); //Need to store the information somewhere that is persisted via ViewState, and we don't have access to ViewState here grid.Attributes.Add("results", results); } /// <summary> /// Handles the Selected event of the source control. Gets the total rows, since it is not possible to access them from the GridView. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs"/> instance containing the event data.</param> private void source_Selected(object sender, ObjectDataSourceStatusEventArgs e) { if (e.ReturnValue is DataView) totalRows = ((DataView)e.ReturnValue).Count; else if (e.ReturnValue is EntitySet) totalRows = ((EntitySet)e.ReturnValue).Count; } #endregion #region Private Methods private static void addResultsToPagerTable(Table tblPager, string results) { //http://michaelmerrell.com/2010/01/dynamically-modifying-the-asp-net-gridview-paging-control/ //Get a handle to the original pager row TableRow pagesTableRow = tblPager.Rows[0]; //Add enough cells to make the pager row bigger than the label we're adding while (pagesTableRow.Cells.Count < 10) pagesTableRow.Cells.Add(new TableCell { BorderStyle = BorderStyle.None }); //Add a new cell in a new row to the table TableRow newTableRow = new TableRow(); newTableRow.Cells.AddAt(0, new TableCell { Text = results, BorderStyle = BorderStyle.None, ColumnSpan = pagesTableRow.Cells.Count }); tblPager.Rows.AddAt(0, newTableRow); } #endregion #region Public Methods /// <summary> /// Adds EventHandlers to the GridView to display results from the ObjectDataSource in the footer. /// </summary> /// <param name="grid">The GridView.</param> /// <param name="source">The ObjectDataSource linked to the GridView.</param> public static void AddResultsToFooter(GridView grid, ObjectDataSource source) { if (grid == null) throw new ArgumentNullException("grid", "grid is null."); if (source == null) throw new ArgumentNullException("source", "source is null."); new GridHelper(grid, source); } #endregion
The amount of li elements that will be rendered into each ul is determined at runtime. Each link in a li belongs to into a specific ul (the one containing a specific caption. Imagine this as a kind of a treeview with nodes and subnodes) During the bind Event I need access to an ASP:HyperLink that will be rendered into the a-element. Which databound ASP.Net control should I pick for this? Looks like a repeater in a repeater, which should make the databinding process ugly. I'm thinking about creating this HTML-Output with StringWriters myself.
i have a FormView, and i already have a Label control that gets the value of theselected propery inside the FormView, so each time the FormView displays data, i have a Label control that displays individual values, according to the value of the FormView, here is the code:
[code]....
What i would like to do is to know how i could add a DataList instead of a Label, and then each time the FormView databinds an item, to show the value of the DataList How would i go about doing that?
I have setup my business object to have a create_date and edit_date members both datetime datatypes. My company want to display the create_date and edit_date fields in a gridview for each transaction. The problem i have is that after insterting a record it will have a valid create_date but no edit_date and when displayed in the gridview it defaults to datetime.minvalue (My default). How on earth do i show an empty field in my gridview for a null datetime field in the database?
I am using similar architecture to the Imar Spaanjaars example of a tiered solution. With a few small tweeks it has worked well for me for ages. I am passing a List<Database> to my object datasource which connects to my gridview.
I have some javascript to iterate the divs in my web page. There is also a ReportViewer control. If I look at the HTML in FireBug in FireFox I can drill down to a div with an id of "oReportDiv". However, my javascript does not pick this up and if I view Source I cannot find it there either. It is the same story in Internet Explorer - I can find the div in the developer tools but not in the source.
The div is buried in nested iFrames and Framesets and all sorts of nasty looking stuff.
I'm working on a custom serverside control and faced to a weird issue.
The control's client-side markup should look like:
[Code]....
But my control renders following markup:
[Code]....
As you can see, attributes for the first <li> element is not rendered.
Here's the Render method:
[Code]....
items collection is filled correctly. Debugging the code showed that AddAttribute is called for first Li element, but the output is rendered incorrectly.
I want to export Asp.Panel content(text, GridViews) with CSS to PDF from C#.NET. I am using iTextSharp and RenderControl with Asp.Panel, but CSS is not rendered in PDF.
How can I solve this problem (with iTextSharp (if is possible) or in another way) ?
I am using a <a href=[URL], an open source e-commerce platform, for one of my projects, and I noticed that they use Master Pages as well as user controls. When I looked some of this up, some people made it appear as if Master Pages were intended to replace user controls. Is this true? In my opinion, if I were to start an ASP.NET app from scratch, I would think a Master Page would be enough, but I guess user controls could be utilized.
My observation so far in the output rendered by a datalist (when I use this user control inside it) is that the value for the name attribute is the same.I want to use this control inside a datalist/repeater such that I'd want a unique value for the input element's name attribute when the datalist/repeater renders. How is this done?
EDIT: My bad obversation. Actually the names are unique. However, when I try to post the page to another web page which outputs the key & value of all the items in Request.Form I don't see the input elements...
I have a page with a data repeater. Each row has a dropdownlist for the user to select a value and the values in every dropdown are the same. I also have an SqlDataSource which each dropdownlist gets its values from as its created. Everything is working as it should but for each dropdown that is rendered a seperate call is made to the database.
suggest a better way for me to do this that means only one call to the database for all dropdowns rendered?
In my XML, it's possible for an apostrophe to appear in a node's value:
[code]....
I've noticed that the text is correctly displayed in the asp:TextBox but not in the INPUT element. I'm assuming that it's because server controls correctly escape the apostrophe. To work around this, I tried changing the Description node in the XML to the following:
<Description>This is section 'A'</Description>
Again, this displayed correctly in the asp:TextBox, but not in the INPUT element.
My next attempt was to wrap the node's value in a CDATA:
<Description><![CDATA[This is section 'A']]></Description>
Finally it was displaying correctly in the INPUT element, but now the asp:TextBox displayed the two "& # 3 9 ;". I've even tried "& a p o s ;" but the result is the same.
What is the best approach for the use of apostrophes in XML where the value can be displayed in either a server control or HTML element?
I use a ListView along with an ObjectDataSource tied to a business object. This object is defined as follows:
public class Employee { public int Id; public string Name; }
When I try setting the DataKeyNames property of the ListView to Id, ASP.net blows up and says: DataBinding: 'Employee' does not contain a property with the name 'Id'. However, when I change the object to that:
public class Employee { public int Id {get; set;} public string Name; }
It works!!!I couldn't find any documentation about this behavior. Why is it not accepting a simple variable for DataKeyNames and instead it insists on a property?
I have a control that inherits CompositeDataBoundControl. Based on the values of the bound data, I create som dynamic controls. In order to preserve state, I need to recreate the control tree on every request(from CreateChildControls):
[code]....
The problem is that on postback the PaymentMethod object is null, so I have no method of knowing what kind of control to recreate. That means that the control state is ruined. If I hardcode the type of payment control to make, it works as expected:
For example when using a gridview. When you specify the columns
BoundField for example won't work if you are binding it to a field instead of a property.
I guess this is so because when the gridview is looking for the DataField property it looks for a property and not a field. Now the question is how can i change this behavior to make it possible to use fields. I know i have to inherit from the gridview, but i don't know where to go from there.
While writing a web application Using MS Web Developer 2010 Express, I noticed a rather disconcerting behavior of the asp:DropDownlist control.When using databinding and you assign a DataValueField the selectedIndexChanged does not fire or change unless the value of the DataValueField changes no matter what the value of the DataTextField. This means that if I have several different text values(States/Provinces) with the same datavalue (US/Canada) I cannot fire an event if the text changes (the textchanged does not fire either) as long as the datavalue doesn't change (all States are US all Provinces are CA). This would seem to be a counter intuitive behavior?
I'm working in a web application and my page is using a databound formview control. When i first enter the page via my code, I am unable to retreive a value from any of my controls -e.g. when i debug, i see that tbDate.text has no value (see code below). How can I retreive the values from the controls on my page e.g text boxes?
Code:
if (!this.IsPostBack) { TextBox tbDate = (TextBox)FormView1.Row.Cells[0].FindControl("txtDate"); }
I am working on this form and I am having a difficult time trying to insert data into the database without having to use gridview, or something like that. I have textboxes and and dropdown lists all over the place and i want enter/selected values to be sent to the DB.
Heres some code:
[Code]....
I understand this code fairly well, but from what i can gather is that is used with DataBound controls. how do i set something like txtProvider.Text to @Provider and also execute the Query?