ASP.net simple repeater question - c#

I'm trying to use the repeat without binding it to a datasource, is this possible?
<asp:Repeater runat="server" ID="rptPageNav">
<ItemTemplate>
<asp:HyperLink runat="server" CssClass="pageLink" ID="pageLink">#</asp:HyperLink>
</ItemTemplate>
</asp:Repeater>
Then in my code, I want to loop through adding the repeater item template for each link available.
for (int i = 0; i < thisTemplate.specification.pagination; i++)
{
}
So the end results should be something like:
<a class="pageLink" href="#">1</a>
<a class="pageLink" href="#">2</a>
<a class="pageLink" href="#">3</a>
<a class="pageLink" href="#">4</a>

Alternatively, if you want only single simple link you don't need Repeater IMO you can have simple Panel then create the links on the fly:
for (int i = 1; i < 5; i++) {
HyperLink link = new HyperLink();
link.CssClass = "pageLink";
link.NavigateUrl = "#";
link.Text = i.ToString();
MyPanel.Controls.Add(link);
}

Create an array of integers up to what you need and bind that to your repeater, using the value as the text for your hyperlink.

No, you have to bind a Repeater to some kind of datasource. Try using an array of ints as #Paddy suggests.
Incidentally, you'll need to modify the markup within the <ItemTemplate> tags to get your hyperlinks to display one above the other as in your example.

MSDN defines asp:Repeater as
A data-bound list control that allows
custom layout by repeating a specified
template for each item displayed in
the list.
Which essentially means we have to bind it to a datasource. Why dont you try and implemt something like this
Markup
<asp:Repeater runat="server" ID="rptPageNav">
<ItemTemplate>
<asp:HyperLink ID="pageLink" runat="server" CssClass="pageLink" NavigateUrl='<%# Eval("Link") %>'><%# Eval("Title") %></asp:HyperLink>
</ItemTemplate>
</asp:Repeater>
Code
public partial class Repeater : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<URL> urls = new List<URL>()
{
new URL(){ Link = "http://www.google.com", Title = "Google"},
new URL(){ Link = "http://www.yahoo.com", Title = "Yahoo"}
};
rptPageNav.DataSource = urls;
rptPageNav.DataBind();
}
}
}
public class URL
{
public string Link { get; set; }
public string Title { get; set; }
}

Related

Appending to div with specific class

How can I append some html to a div with a specific class name?
frontend:
<div class="school-team-popup"></div>
backend:
StringBuilder _html = new StringBuilder();
_html.AppendFormat("<li>Hi there</li>");
I would like to append _html inside the school-team-popup div. How can I do this from the backend?
I'm going to explain the Web Forms way of doing things.
If you have some static markup that you want to selectively show/hide on your page, that's generally accomplished by setting the Visible property of the control.
<%-- This is in your ASPX markup (.aspx) --%>
<asp:Panel runat="server" id="HelloWorldPanel">
<p>Hello, world!</p>
</asp:Panel>
//This is in your code behind (.aspx.cs)
//hide the panel
HelloWorldPanel.Visible = false;
//show the panel
HelloWorldPanel.Visible = true;
If you're trying to grab dynamic data from some other source and display it on the page, you would declare the markup on your page to show this data, and then bind the data to the markup. There are many controls you can bind data to.
One example of a control you can bind data to is a repeater. Repeaters are good when you want tight control over the markup that gets rendered on the page. You bind them to some enumerable object such as a List<T> and then it will repeat some markup for each element in the enumerable object.
//This is in your project somewhere
namespace MyNamespace
{
public class Product
{
public int Id { get; set; }
public int Name { get; set; }
}
}
<%-- This is in your ASPX markup (.aspx) --%>
<ul>
<asp:Repeater runat="server" id="ProductRepeater" ItemType="MyNamespace.Product">
<ItemTemplate>
<li><%#: Item.Id %> - <%#: Item.Name %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
//this is in your code behind (.aspx.cs)
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostback)
{
List<Product> products = MyDataLayer.GetProducts();
ProductRepeater.DataSource = products;
ProductRepeater.DataBind();
}
}

How do you get values from dynamic controls in a ListView on postback?

I've recently had to go back to dealing with webforms code and have run into an issue trying to update an existing page that shows a list of survey responses.
I have a ListView showing details of people who have answered a survey.
When you click on an icon in the row that row enters edit mode and shows their information (name, email etc) as input boxes.
So far so good, now I need to add the questions and the answers for that survey and that person. Writing them out is easy, but when the postback happens the row goes back to the ItemTemplate and the controls are gone.
I know with dynamic controls you are supposed to create the in Page_Init so webforms can rebind them, but here the controls aren't created until the ListItem ItemEditing event, and the data saved in the ItemUpdating event.
I'm stuck on how I could make the controls in the right place with the right data at the right point in the lifecycle. Right now I'm trying to pull the values from Request.Form but with a CheckboxList it's hard to figure out what has been selected.
Edit: New example that should actually run
<%# Page Language="C#" AutoEventWireup="true" CodeFile="QuestionExample.aspx.cs" Inherits="QuestionExample" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<table>
<asp:ListView runat="server" ID="LV" OnItemEditing="LV_OnItemEditing" OnItemUpdating="LV_OnItemUpdating">
<LayoutTemplate>
<tr>
<td><asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder></td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<asp:LinkButton ID="EditButton" runat="server" CommandName="Edit" Text="Edit"/>
ID: <asp:Label runat="server" ID="lblLeadID" Text="<%# ((Lead)Container.DataItem).LeadID %>" /> Name: <%# ((Lead)Container.DataItem).Name %><br/>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="UpdateButton" runat="server" CommandName="Update" Text="Update" />
ID: <asp:Label runat="server" ID="lblLeadID" Text="<%# ((Lead)Container.DataItem).LeadID %>" /> <asp:Label runat="server">Name</asp:Label>
<asp:TextBox runat="server" id="tbName" Text="<%# ((Lead)Container.DataItem).Name %>"></asp:TextBox>
<asp:Panel runat="server" id="pnlQuestions"></asp:Panel>
</EditItemTemplate>
</asp:ListView>
</table>
</form>
</body>
</html>
Then the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class QuestionExample : Page
{
#region fake data
protected List<Question> Questions = new List<Question>()
{
new Question { QuestionID = 0, QuestionType = QuestionType.Textbox, QuestionText = "TextBox", Options = null },
new Question { QuestionID = 1, QuestionType = QuestionType.DropDownList, QuestionText = "DDL", Options = new List<string> { "A", "B", "C"} },
};
protected List<Lead> Leads = new List<Lead>
{
new Lead { LeadID = 0, Name = "Bob", Answers = new Dictionary<string, string> { { "TextBox", "Hi" }, { "DDL", "B" } } },
new Lead { LeadID = 1, Name = "Fred", Answers = new Dictionary<string, string> { { "TextBox", "Stuff" }, { "DDL", "C" } } },
};
#endregion
protected void Page_Load(object sender, EventArgs e)
{
LV.DataSource = Leads;
LV.DataBind();
}
protected void LV_OnItemEditing(object sender, ListViewEditEventArgs e)
{
LV.EditIndex = e.NewEditIndex;
LV.DataBind();
var leadLabel = (Label)LV.Items[e.NewEditIndex].FindControl("lblLeadID");
var leadID = int.Parse(leadLabel.Text);
var panel = (Panel)LV.Items[e.NewEditIndex].FindControl("pnlQuestions");
var lead = Leads.First(l => l.LeadID == leadID);
foreach (var answer in lead.Answers)
{
var question = Questions.First(q => q.QuestionText == answer.Key);
panel.Controls.Add(CreatQuestionControl(question, lead, true));
}
}
protected Control CreatQuestionControl(Question question, Lead lead, bool setAnswers)
{
Control result = null;
switch (question.QuestionType)
{
case QuestionType.Textbox:
var tb = new TextBox();
if (setAnswers)
{
var answer = lead.Answers[question.QuestionText];
tb.Text = answer;
}
result = tb;
break;
case QuestionType.DropDownList:
var ddl = new DropDownList { DataSource = question.Options };
ddl.DataBind();
if (setAnswers)
{
var answer = lead.Answers[question.QuestionText];
ddl.SelectedValue = answer;
}
result = ddl;
break;
}
return result;
}
protected void LV_OnItemUpdating(object sender, ListViewUpdateEventArgs e)
{
// Get input data here somehow
LV.EditIndex = -1;
}
}
public class Lead
{
public int LeadID { get; set; }
public string Name { get; set; }
public Dictionary<string, string> Answers { get; set; }
}
public class Question
{
public int QuestionID { get; set; }
public string QuestionText { get; set; }
public QuestionType QuestionType { get; set; }
public List<string> Options { get; set; }
}
public enum QuestionType
{
Textbox = 0,
DropDownList = 1,
}
Without seeing your code it's difficult to give a complete answer, but basically you need to recreate the control tree, including the dynamically created controls, on postback.
You can do this, for example, in the Page_Load event handler.
You can store any data you need to recreate the control tree in ViewState so that it is available on PostBack.
I'm not sure what you mean by:
... when the postback happens the row goes back to the ItemTemplate
I would expect EditIndex to stay unchanged after a postback, unless you explicitly modify it, and therefore the edit row to be unchanged, and EditItemTemplate to be used.
If you can post a simplified sample that illustrates your problem I (or someone else) may be able to help further.
UPDATE
Based on the posted code, you need to recreate the dynamic controls in the ItemUpdating event handler and add them to the control tree in the same order as you created them in the ItemEditing event handler. I.e. you probably need to repeat the code:
var questionPannel = lL.Items[e.ItemIndex].FindControl("lead_table") as HtmlTable;
var campaignQuestionsTableRow = questionPannel.FindControl("campaign_questions") as HtmlTableRow;
var questions = GetQuestions();
foreach(var question in questions)
{
// This builds a WebControl for the dynamic question
var control = CreateQuestionControl(question);
campaignQuestionsTableRow.AddControl(control);
}
UPDATE 2
When updating, you need to recreate the dynamic controls on PostBack. Change your Page_Load event handler to something like:
protected void Page_Load(object sender, EventArgs e)
{
LV.DataSource = Leads;
LV.DataBind();
if (IsPostBack)
{
if (LV.EditIndex >= 0)
{
var leadLabel = (Label)LV.Items[LV.EditIndex].FindControl("lblLeadID");
var leadID = int.Parse(leadLabel.Text);
var panel = (Panel)LV.Items[LV.EditIndex].FindControl("pnlQuestions");
var lead = Leads.First(l => l.LeadID == leadID);
foreach (var answer in lead.Answers)
{
var question = Questions.First(q => q.QuestionText == answer.Key);
panel.Controls.Add(CreatQuestionControl(question, lead, true));
}
}
}
}
On the first Postback (click on Edit), EditIndex will be -1, and the dynamic controls are created in the OnItemEditing handler.
On the second Postback (click on Update), EditIndex will be the index of the line you're editing, and you need to recreate the dynamic controls in Page_Load. If you do this, you'll find your posted values when you get to the OnItemUpdating event handler.
While I think it's worthwhile understanding how to use dynamic controls in this way, in a production app I'd probably use a Repeater inside the EditItemTemplate as suggested by Elisheva Wasserman. The Repeater could contain a UserControl that encapsulates the logic to hide/show UI elements based on the question type.
You should use an inside Repeater or listView, which will be bind on item_edit event, instead of recreating dynamics controls every post.
this way:
<asp:ListView ID="lL" runat="server" OnItemEditing="lL_ItemEditing" OnItemUpdating="lL_ItemUpdating">
<itemtemplate>
Read only view here...
</itemtemplate>
<edititemtemplate>
<asp:LinkButton D="UpdateButton" runat="server" CommandName="Update" />
<table runat="server" ID="lead_table" class="lead_table">
<tr id="Tr1" style="background-color:#EEEEEE;" runat="server" >
<td>Name: <asp:TextBox ID="Name" /></td>
Other Fixed controls...
</tr>
<tr runat="server" ID ="campaign_questions">
<asp:Repeater id='repetur1' runat="server">
<ItemTemplate>
<asp:Label id='lblCaption' runat='server" Text='<%Eval("QuestionTitle")%>' />
<asp:TextBox id='name' runat="server" />
</ItemTemplate>
</asp:Repeater>
</tr>
</table>
on code behind
protected void lL_ItemEditing(object sender, ListViewEditEventArgs e)
{
var questionPannel = lL.Items[e.ItemIndex].FindControl("lead_table") as HtmlTable;
var campaignQuestionsTableRow = questionPannel.FindControl("campaign_questions") as HtmlTableRow;
// bind fixed controls
var lead = GetLead();
var nameControl = ((TextBox)lL.Items[e.ItemIndex].FindControl("Name"))
nameControl.Text = lead.Name;
// bind dynamic controls
var questions = GetQuestions();
var rep= (Repeater)lL.Items[e.ItemIndex].FindControl("repeatur1");
rep.DataSource=questions;
rep.DataBind();
}
protected void lL_ItemUpdating(object sender, ListViewUpdateEventArgs e)
{
// Get fixed fields
// var lead = GetLead();
lead.Name = ((TextBox)lL.Items[e.ItemIndex].FindControl("Name")).Text.Trim();
Repeater rep=(Repeater)e.FindControl("repeatur1"));
foreach (RepeaterItem item in rep.Items)
{
TextBox t=item.FindControl("txtName") as TextBox;
//do your work here
}
// Switch out of edit mode
lL.EditIndex = -1;
}

ASP.NET find control by id

I am doing a simple web site using asp.net and i am having troubles finding my or objects by id in the code behind in c#. I have something like this:
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
the rest is irrelevant, and then i use this in the code behind:
Table table = (Table)FindControl("camas");
i also tried:
Table table = (Table)camas;
and
Control table= (Table)FindControl("camas");
and each one of this lines gives me Null. am i doing something wrong ?
EDIT: From your answers i did this:
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
and tried all the things stated above. same result.
EDIT2: Whole Code:
C#
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControl("camas");
HiddenField NCamasHF = (HiddenField)FindControl("NCamas");
int NCamas = Convert.ToInt32(NCamasHF);
HiddenField NColunasHF = (HiddenField)FindControl("NColunas");
HiddenField CorMasc = (HiddenField)FindControl("CorMasc");
HiddenField CorFem = (HiddenField)FindControl("CorFem");
int NColunas = Convert.ToInt32(NColunasHF);
TableRow Firstrow = new TableRow();
table.Rows.Add(Firstrow);
for (int i = 1; i <= NCamas; i++)
{
if (i % NColunas == 0)
{
TableRow row = new TableRow();
table.Rows.Add(row);
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
row.Cells.Add(cell);
}
else
{
TableCell cell = new TableCell();
cell.BackColor = System.Drawing.Color.LightGreen;
cell.CssClass = "celula";
Firstrow.Cells.Add(cell);
}
}
}
asp.net
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<asp:SqlDataSource
ID="ParametrosBD"
ConnectionString ="<%$ ConnectionStrings:principal %>"
ProviderName = "System.Data.SqlClient"
SelectCommand = "SELECT par_Id, par_NCamas, par_NColunas, par_CorMasculino, par_CorFeminino FROM Parametros WHERE par_Id=1"
runat="server">
</asp:SqlDataSource>
<asp:ListView ID="InternamentosListView" runat="server"
DataSourceID="InternamentosBD">
<LayoutTemplate>
<table id="camas" runat="server">
</table>
</LayoutTemplate>
<ItemTemplate>
<asp:HiddenField ID="NCamas" runat="server" Value='<%# Bind("par_NCamas") %>' />
<asp:HiddenField ID="NColunas" runat="server" Value='<%# Bind("par_NColunas") %>' />
<asp:HiddenField ID="CorMasc" runat="server" Value='<%# Bind("par_CorMasculino") %>' />
<asp:HiddenField ID="CorFem" runat="server" Value='<%# Bind("par_CorFeminino") %>' />
<tr id="cama"></tr>
</ItemTemplate>
</asp:ListView>
</asp:Content>
To expand on #Yura Zaletskyy's recursive find control method from MSDN -- you can also use the Page itself as the containing control to begin your recursive search for that elusive table control (which can be maddening, I know, I've been there.) Here is a bit more direction which may help.
using System;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI;
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Table table = (Table)FindControlRecursive(Page, "camas");
if (table != null)
{
//Do awesome things.
}
}
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
}
As you already added runat="server" is step 1. The second step is to find control by id, but you need to do it recursively. For example consider following function:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
None of the existing answers mention the obvious built-in solution, FindControl.
Detailed here, FindControl is a function that takes as a string the id of a control that is a child of the calling Control, returning it if it exists or null if it doesn't.
The cool thing is that you can always call it from the Page control which will look through all controls in the page. See below for an example.
var myTextboxControl = (TextBox)Page.FindControl("myTextboxControlID);
if (myTextboxControl != null) {
myTextboxControl.Text = "Something";
}
Note that the returned object is a generic Control, so you'll need to cast it before you can use specific features like .Text above.
You need to have runat="server" for you to be able to see it in the codebehind.
e.g.
<table id="camas" runat="server">
Ok. You have the table within a list view template. You will never find the control directly on server side.
What you need to do is find control within the items of list.Items array or within the item data bound event.
Take a look at this one- how to find control in ItemTemplate of the ListView from code behind of the usercontrol page?
When you're using a master page, then this code should work for you
Note that you're looking for htmlTable and not asp:Table.
// add the namespace
using System.Web.UI.HtmlControls;
// change the name of the place holder to the one you're using
HtmlTable tbl = this.Master.FindControl("ContentPlaceHolder1").FindControl("camas") as HtmlTable;
Best,
Benny
You need to add runat server like previously stated, but the ID will change based on ListView row. You can add clientidmode="Static" to your table if you expect only 1 table and find using InternamentosListView.FindControl("camas"); otherwise, you will need to add ItemDataBound event.
<asp:ListView ID="InternamentosListView" runat="server" DataSourceID="InternamentosBD" OnItemDataBound="InternamentosListView_ItemDataBound">
<LayoutTemplate>
<table id="camas">
<asp:PlaceHolder runat="server" ID="TablePlaceHolder"></asp:PlaceHolder>
</table>
</LayoutTemplate>
You will need to introduce in code behind
InternamentosListView_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Table tdcamas = (Table)e.Item.FindControl("camas");
}
}

Creating buttons/href from a list of names on the server side with javascript?

I have a list of button names and uri's containing links to other pages in my website. This is stored in my database. I also have a javascript function that can create buttons dynamically preferably when the page loads. Now what I need is on the server side to iterate through the list of button names and create a button for every button in the list?
Is this possible. I was thinking of maybe using the string builder to build some html to create the buttons or the method I like more is to call the javascript everytime I need a new button.
Here is my javascript function:
function createHref(Name, Uri) {
var leftDiv = document.createElement("div"); //Create left div
leftDiv.id = "left"; //Assign div id
leftDiv.setAttribute("style", "float:left; width:66.5%; line-height: 26px; text-align:left; font-size:12pt; padding-left:8px; height:26px;"); //Set div attributes
leftDiv.style.background = "#FF0000";
a = document.createElement('a');
a.href = Uri;
a.innerHTML = Name
leftDiv.appendChild(a);
document.body.appendChild(leftDiv);
}
Since this is ASP.NET I would use a Repeater and set the datasource to the button data you pull from your database.
For examples sake, I will assume you have a custom object MyButton that maps to your data:
public class MyButton
{
public MyButton()
{}
public string Name { get; set; }
public string Href { get; set; }
}
You would then have some markup for the repeater:
<asp:Repeater ID="rptMyButtons" runat="server" OnItemDataBound="rptMyButtons_ItemDataBound">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<asp:HyperLink ID="hypUrl" runat="server" />
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
You would then bind your data to the repeater and set some properties on the objects:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
rptMyButtons.DataSource = //your data from the database
rptMyButtons.DataBind();
}
}
protected void rptMyButtons_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
{
MyButton button = (MyButton)e.Item.DataItem;
HyperLink hypUrl = (HyperLink)e.Item.FindControl("hypUrl");
hypUrl.Text = button.Name;
hypUrl.NavigateUrl = button.Href;
}
}
It seems like you may be trying to build a sitemap?
I have a list of button names and uri's containing links to other pages in my website
Which is why I have used a <ul> and <li>'s to contain your buttons in a list which makes more sense. It is quite easy to change this back to a <div> however.

How to create capital letter row for a list of names in an ASP Repeater

I'm using an asp repeater to display a list of names and I want to display the current letter as a type of grouping header, like in an index page.
The data is sorted alphabetically before binding, but i'm finding it difficult to insert the 'A' and 'B' before the names are displayed.
Add a Panel control to your ItemTemplate with visibility set to False. When you are binding the repeater (assuming you are subscribing to the ItemDataBound event), run a check to see if the first letter has changed. If it has, set the panel's visibility to true and print out the letter.
Let me know if you need some example code.
EDIT: EXAMPLE CODE
For clarity sake, "AlphaHeaders" is what we will call the "A", "B", "C" letters that we want to display
aspx code
The Repeater will look like so:
<table>
<asp:Repeater id="rptRepeater" runat="server" OnItemDataBound="rptNames_OnItemDataBound">
<ItemTemplate>
<asp:Panel id="pnlAlphaHeader" runat="server" visible="False">
<tr><td><asp:Label id="lblAlphaHeader" runat="server" /></td></tr>
</asp:Panel>
<tr><td><asp:Label id="lblName" runat="server" /></td></tr>
</ItemTemplate>
</asp:Repeater>
</table>
aspx.cs code
First, you need a variable that holds the current AlphaHeader:
private string _AlphaHeaderCurrent = String.Empty;
Then you will do your work on the repeater's OnItemDataBound event:
protected void rptNames_OnItemDataBound(object sender, System.Web.UI.WebControls.RepeaterItemEventArgs e)
{
if ((e.ItemType==ListItemType.Item) || (e.ItemType==ListItemType.AlternatingItem)) {
string name = e.Item.DataItem("Name").ToString();
//check if the first letter of the current name is new. If it is new, we print out the header
if(!name.StartsWith(this._AlphaHeaderCurrent)) {
this._AlphaHeaderCurrent = name.SubString(1);
((Panel)e.ItemFindControl("pnlAlphaHeader")).Visible = true;
((Label)e.Item.FindControl("lblAlphaHeader")).Text = the._AlphaHeader;
}
((Label)e.Item.FindControl("lblName")).Text = name;
}
}
You sort before you bind.
That is, bind the sorted result set.
Without seeing the values you have, however, it is not possible to tell exactly how to do so.
Update - from your comment, I would say you need to change your binding source to something like Dictionary<string,IList<string>>.
With such a structure, you could bind by key (sorted) and sublist (secondary sort).
You need to sort your data before bind it to the repeater.
You can use nested repeaters (repeater inside repeater). Like category and subcategory.
In first repeater you can list all your names and make a condition starts with A. Then in sub repeater you can show all names. You will also use itemdatabound event to bind second repeater.
<asp:Repeater id="rptFirstLetters" runat="server" OnItemDataBound="rptChars_OnItemDataBound">
<ItemTemplate>
<div>"<%#Eval("letters") %>"
<asp:Repeater id="rptNames" runat="server">
<ItemTemplate>
<%#Eval("names") %>
</ItemTemplate>
</asp:Repeater>
</div> // bind all letters
</ItemTemplate>
Not really a nice way of doing this to be honest, repeaters generally result in ugly code I've found. The hierarchical approach from kad1r is probably the nicest if you can set it up, but there are alternatives, depending on your implementation details; I kind of prefer this in some ways as it keeps the markup very clean, and as I have a non-programmer design guy that is a plus for me.
ASPX:
<%# Page language="C#" Src="test.CODE.cs" Inherits="test_Page" %>
<asp:Repeater ID="TestRepeater" runat="server">
<ItemTemplate>
<asp:PlaceHolder Visible='<%# Eval("IsFirstInGroup") %>' runat="server">
<strong><%# Eval("Initial") %></strong><br/>
</asp:PlaceHolder>
<%# Eval("Name") %><br/>
</ItemTemplate>
</asp:Repeater>
CODE BEHIND:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public class test_Page : Page
{
protected Repeater TestRepeater;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
String[] names = new String[]
{
"Alpha, John",
"Altman, Mary",
"Asher, Cyril",
"Bachman, Turner",
"Beta, Rob",
"Bexman, Norah",
"Clark, Freddy"
};
List<_DispItem> l = new List<_DispItem>();
for (int i = 0; i < names.Length; i++)
l.Add(new _DispItem() { Name = names[i], IsFirstInGroup = (i == 0 || names[i - 1][0] != names[i][0]) });
TestRepeater.DataSource = l;
TestRepeater.DataBind();
}
private class _DispItem
{
public String Name { get; set; }
public String Initial { get { return Name.Substring(0, 1); } }
public bool IsFirstInGroup { get; set; }
}
}

Categories

Resources