Allocate number of columns to repeater when the page is loaded - asp.net

I am binding a dataset to asp repeater.
<asp:Repeater id="rptDataset" runat="server">
<table>
<HeaderTemplate>
<tr>
<th>Col1</th>
<th>Col2</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("c1") %></td>
<td><%# Eval("c2") %></td>
</tr>
</ItemTemplate>
</asp:Repeater>
Now I have varying number of columns, that won't be known until the page is loaded. So I'm modifying the header like this
<HeaderTemplate>
<tr>
<th>Col1</th>
<th>Col2</th>
<% for (int i=0; i<NoOfColumn; i++){
Response.Write("<th>ColN</th>")
} % >
</tr>
</HeaderTemplate>
Which correctly showed all column headers.
What should I modify <ItemTemplate> so it could show all the column data?
I've tried something like
<% Response.Write("<td><%# Eval("c1") %></td>") %>
which would result an error due to the nested <% %> sign.
Also tried
<% Response.Write(DataBinder.Eval(Container.DataItem, "c1")) %>
but it said Container cannot be resolved.

So you have two options, quick hack and proper pretty solution.
Quick hack
Create all necessary html in a string and output it in Literal control. Make sure to use PassThrough mode not to have html encoded:
<ItemTemplate>
<%# GetDataRow(Container.DataItem) %>
</ItemTemplate>
protected string GetDataRow(object dataItem)
{
StringBuilder output = new StringBuilder();
output.Append("<tr>");
for (int i=0; i<NoOfColumn; i++)
{
output.Append("<td>");
output.Append(DataBinder.Eval(dataItem, "c"+i));
output.Append("</td>");
}
output.Append("</tr>");
return output.ToString();
}
Pretty solution
Define your own custom template implementing ITemplate. A complete example of how this is done can be found here. It will take more work, but, as it's usually the case with pretty solutions, result will be much more readable, maintainable and reusable.

Finally I have it solved by applying nested Repeater.
<asp:Repeater runat="server" ID="rptRow">
<ItemTemplate>
<tr>
<td><%# Eval("c1") %></td>
<td><%# Eval("c2") %></td>
<asp:Repeater runat="server" ID="rptCol">
<ItemTemplate>
<td><%# Eval("cn") %></td>
</ItemTemplate>
</asp:Repeater>
</tr>
</ItemTemplate>
</asp:Repeater>

Related

Databinder inside a "for" loop in an ASPX page

I'm still trying to understand how I can take advantage from DataBinder ( Is there a way to use a DataBinder.Eval statement as an index of a specific array in an ASPX page? ).
I'm currently building tables with the help of repeater and I would like to use a loop defining the Item label dynamically, to allow more interactions.
Currently, this test code is working:
<asp:Repeater id="Fish" runat="server">
<table>
<ItemTemplate>
<tr>
<td><%# Container.DataItem("ITEM")%></td>
<td><%# Container.DataItem("AGG")%></td>
</tr>
</ItemTemplate>
</table>
</asp:Repeater>
But as you can imagine, this type of structure doesn't allow to choose dynamically the columns that are displayed from the columns to be ignored.
I was thinking that by using a "for" loop structure, I would be able to choose dynamically which column could be displayed. And I tried this as a test:
Public Test_id() As String
Public Test_idp As String
<% Test_id = New String() {"id", "Agg"} %>
<asp:Repeater id="Fish" runat="server">
<table>
<ItemTemplate>
<tr>
<% For Each Test_idp as String In Test_id%>
<td><%# Container.DataItem(Test_idp)%></td>
<% Next Test_idp%>
</tr>
</ItemTemplate>
</table>
</asp:Repeater>
which is not working... and is granted by the following error message:
Overload resolution failed because no Public 'Item' is most specific for these arguments:
'Public Overrides ReadOnly Property Item(name As String) As System.Object': Not most specific.
'Public Overrides ReadOnly Property Item(i As Integer) As System.Object': Not most specific.
Any idea?
Edit:
to answer Mike C's question, I have tried DataBinder.Eval(Container.DataItem, Test_idp) instead of Container.DataItem(Test_idp). It still does not work, but the error is different:
System.ArgumentNullException: value cannot be null
Test_Idp is an Object (since it wasn't declared otherwise).
Therefore, the compiler cannot figure out which of those overloads to call.
You need to explicitly declare it As String.
You can use a nested repeater for the columns.
<asp:Repeater id="Fish" runat="server">
<table>
<ItemTemplate>
<tr>
<asp:Repeater id="columns" runat="server">
<ItemTemplate>
<td><%# ((RepeaterItem)Container.Parent.Parent).DataItem("ITEM")%></td>
<td><%# ((RepeaterItem)Container.Parent.Parent).DataItem("AGG")%></td>
</ItemTemplate>
</asp:Repeater>
</tr>
</ItemTemplate>
</table>
</asp:Repeater>

Passing Params From Aspx

So I had have a table populating with data but I was wondering how I could pass two bits of data from a row depending on which link at the end of the row is clicked.
<%WebReceiptSummary[] receipts = GetReceipts();
if (receipts != null)
{
for (int i = 0; i < receipts.Length; i++)
{%>
<tr>
<td><%= receipts[i].Type%></td>
<td><%= receipts[i].PolicyNo%></td>
<td><%= receipts[i].Date%></td>
<td class="c"><%= receipts[i].Amount%></td>
<td class="r"><asp:LinkButton OnCommand="PDFLinkClick"
CommandArgument="<%= receipts[i].PDF %>&<% receipts[i].PolicyNo %>" runat="server">View PDF</asp:LinkButton></td>
</tr>
<% }
}
%>
Obviously my CommandArgument just passes back the string <%= receipts[i].PDF %>&<% receipts[i].PolicyNo %> not the values. What would be the best way of doing this? I was also thinking of using;
<asp:HiddenField ID="hiddenIsCaptchaReadyValidate" runat="server" Value=false/>
But I have the same problem here where the value is placed within quotes and also it means I need to create two hiddenfields for ever row which isn't the most efficient way of doing this. Thoughts?
It is not possible to have <%= %> commands as part of an attribute when added via the mark-up.
Can I recommend that instead of using the for loop in the ASPX, you instead use the <asp:Repeater> control? This will also allow you to set the CommandAttribute value from the code-behind.
An example...
<asp:Repeater runat="server" id="receipts" OnItemDataBound="receipts_ItemDataBound">
<ItemTemplate>
<tr>
<td><%#((WebReceiptSummary)Container.DataItem).Type%></td>
<td><%#((WebReceiptSummary)Container.DataItem).PolicyNo%></td>
<td><%#((WebReceiptSummary)Container.DataItem).Date%></td>
<td class="c"><%#((WebReceiptSummary)Container.DataItem).Amount%></td>
<td class="r"><asp:LinkButton ID="pdfLink" OnCommand="PDFLinkClick" runat="server">View PDF</asp:LinkButton></td>
</tr>
</ItemTemplate>
</asp:Repeater>
In your Init or Load in code behind...
receipts.DataSource = GetReceipts();
receipts.DataBind();
Then...
protected void receipts_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
((LinkButton)e.Item.FindControl("pdfLink")).CommandArgument =
((WebReceiptSummary)e.DataItem).PDF + ((WebReceiptSummary)e.DataItem).PolicyNo;
}
UPDATE
Thinking about it, rather than using the code-behind setting of the CommandArgument, I think (I haven't tested this yet) you could actually do the following without needing the receipts_ItemDataBound function...
<td class="r"><asp:LinkButton ID="pdfLink" OnCommand="PDFLinkClick" runat="server"
CommandArgument="<%#((WebReceiptSummary)Container.DataItem).PDF + ((WebReceiptSummary)Container.DataItem).PolicyNo%>"
>View PDF</asp:LinkButton></td>
UPDATE 2
All instances of Container.DataItem in the above examples, have been changed into the tight-bound ((WebReceiptSummary)Container.DataItem)

How can I use a FOR loop inside a REPEATER to create <TD>'s in a <TABLE>?

I have a repeater that is bound to a List(of T) object collection. It's a list of Inventory objects. Each Inventory object also contains a List(of T) which is a list of Date / Inventory Count pairs. When the repeater is creating a table, I need to create a TD for each of the Date / Inventory Counts. Since the number of Date / Inventory Counts is not set until runtime (using NumWeeks variable), I need to vary the number of TD's in my repeater. This is essentially what I want:
<asp:Repeater ID="rptReport" runat="server">
<ItemTemplate>
<tr>
<td><%#DataBinder.Eval(Container.DataItem, "Department")%></td>
<td><%#DataBinder.Eval(Container.DataItem, "Description")%></td>
<% For x = 0 To NumWeeks%>
<td><%#DataBinder.Eval(Container.DataItem, "Values")(x).Value()%></td>
<% Next%>
</tr>
</ItemTemplate>
</asp:Repeater>
You need to place another repeater inside this repeater and assign the datasource to that inner repeater in the "ItemDataBound" event of the parent repeater. This should solve your issue.
Hope this is helpful!!
Another option would be that you create a UserControl containing a Repeater for the inner loop. You can assign the "Values" as a property of the UserControl. Something like this:
<asp:Repeater ID="rptReport" runat="server">
<ItemTemplate>
<tr>
<td><%# Eval("Department") %></td>
<td><%# Eval("Description") %></td>
<uc:WeekControl NumWeeks="<%#NumWeeks %>" Values='<%# EVal(Values)%> />
</tr>
</ItemTemplate>
</asp:Repeater>
I needed that for loop I tried another approach and it worked.
in my .cs file I created a public string and used it inside the repeater. It works fine.
public string somethingloop
for (int i = 0; i < dolar; i++)
{
somethingloop += "<i class='fa fa-dollar icon highlighted'></i>";
}
and in repeater inside anywhere in the itemtemplate
<asp:Repeater ID="rptReport" runat="server">
<ItemTemplate>
<%= somethingloop %>
<tr>
<td><%# Eval("Department") %></td>
<td><%# Eval("Description") %></td>
<uc:WeekControl NumWeeks="<%#NumWeeks %>" Values='<%# EVal(Values)%> />
</tr>
</ItemTemplate>
</asp:Repeater>

ListView Asp.Net control - Assigning strings to Listview columns

ListView Web Control question:
I developed a report service web application using Asp.Net 3.5 and ReportingService2010.asmx. I retrieved the ItemHistorySnapshots with the following code:
ItemHistorySnapshot[] itemSnapshots = null;
itemSnapshots = rs.ListItemHistory(strChildNode);
foreach(ItemHistorySnapshot snapshot in itemSnapshots) {
listview.add (snapshot.HistoryID.Tostring());
listview.add (snapshot.Size.Tostring());
listview.add(snapshot.DateTime.Tostring());
}
I want to create a ListView with 3 columns HistoryID, Size, DateTime and want to assign the string values in foreach loop.
Please let me know how to assign the string values to ListView. I want to know the source control code for listview also. Thank you very much.
You can use an repeater and bind the data to it, like this:
Code behind:
ItemHistorySnapshot[] itemSnapshots = null;
itemSnapshots = rs.ListItemHistory(strChildNode);
rpt.DataSource = itemSnapshots.Select(s => new
{
HistoryID = s.HistoryID.ToString(),
Size = s.Size.ToString(),
DateTime = s.DateTime.ToString(),
});
rpt.DataBind();
Aspx Page:
<asp:Repeater id="rpt" runat="server">
<HeaderTemplate>
<table border="1" width="100%">
<tr>
<th>HistoryID</th>
<th>Size</th>
<th>DateTime</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# Eval("HistoryID") %></td>
<td><%# Eval("Size") %></td>
<td><%# Eval("DateTime") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>

Seeking Advice: Updating a FormView Based on DropdownList Value

Greetings!
I'm looking for some advice regarding an approach to displaying data in a FormView based on a selection of a DropDownList within that FormView control. For example, I have a UserControl with the following:
<asp:XmlDataSource ID="xdsMyXmlData" runat="server" EnableCaching="false" XPath="Root/Membership" />
<asp:FormView ID="fvwMyFormView" runat="server" DataSourceID="xdsMyXmlData">
<ItemTemplate>
<div>
<h2><%# XPath("Title") %></h2>
<fieldset>
<asp:DropDownList ID="ddlMemberTypes" runat="server" DataSource='<%# XPathSelect("MenuItems/*") %>'></asp:DropDownList>
</fieldset>
<table>
<thead>
<tr>
<th><%# XPath("Columns/Name") %></th>
<th><%# XPath("Columns/Age") %></th>
<th><%# XPath("Columns/DateJoined")%></th>
</tr>
</thead>
<tbody>
<asp:Repeater ID="rptMembershipInfo" runat="server" DataSource='<%# XPathSelect("Members/*") %>'>
<ItemTemplate>
<tr>
<th><%# XPath("Data/Name") %></th>
<td><%# XPath("Data/Age") %></td>
<td><%# XPath("Data/DateJoined") %></td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
</div>
</ItemTemplate>
</asp:FormView>
The UserControl's OnLoad() looks like this so far:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string l_XmlData = MyControllerClass.GetMembershipTableXml(0);
xdsMyXmlData.Data = l_XmlData;
}
I would like to be able to pass the value of the DropDownList's selected item into GetMembershipTableXml() in order to retrieve the corresponding XML and then use it to populate the values of the FormView. What would the best way be to do this? Doing a Response.Redirect back to the current page using the selected DropDownList value as a query string variable? I'm hoping there's a better approach. What do you think?
You can create an event for OnSelectedItemChanged on your DropDownList; when this occurs, you can grab the selected item, and call your GetMembershipTableXml function.
Finally, dont forget to call DataBind on your FormView control to update the values :)
I think that's what you're after, hopefully it helps!

Resources