Populating a listbox control in asp.net - c#

I have a code block that returns a list of employee object.
The resultset contains more than one employee record. One of the elements, is EmployeeID.
I need to populate listview (lstDepartment) with only the EmployeeID. How can I do that?
lstDepartment.DataSource = oCorp.GetEmployeeList(emp);
lstDepartment.DataBind()

You have to also specify this:
lstDepartment.DataSource = oCorp.GetEmployeeList(emp);
lstDepartment.DataTextField = "EmployeeID";
lstDepartment.DataValueField = "EmployeeID";
lstDepartment.DataBind()

One way would be to use an anonymous type:
lstDepartment.DataSource = oCorp.GetEmployeeList(emp)
.Select(emp => new { emp.EmployeeID });
lstDepartment.DataBind();
Edit: But you also could select all columns but diplay only one. A ListView is not a ListBox or DropDownList. Only what you use will be displayed. So if you're ItemTemplate looks like:
<ItemTemplate>
<tr runat="server">
<td>
<asp:Label ID="LblEmployeeID" runat="server" Text='<%# Eval("EmployeeID") %>' />
</td>
</tr>
... only the EmployeeID is displayed, no matter whatelse is in your DataSource.

You may mention what to display in your ItemTemplate of ListView
<asp:ListView ID="lstDepartment" runat="server">
<ItemTemplate>
<p> <%#Eval("EmployeeID") %> </p>
</ItemTemplate>
</asp:ListView>

Related

Repeater grouping items from single database

I have a table with headers(example): Group, DisplayName, EditableData, description.
I have been trying for the last few days to learn repeaters to sort the information based on the Group so I can get something that looks like the following layout. This is a user control I am trying to put together.
Group1
------------------
Name1 EditableData Some Description
Name2 EditableData Some Description
Group2
------------------
Name3 EditableData Some Description
Name4 EditableData Some Description
I have looked a the following other examples online:
Nested repeaters - grouping data and
Nested Repeaters in ASP.NET
I believe I do not properly understand how repeaters work enough to deal with nesting or datasource.
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
Group: <%#Eval("Group")%><br />
<%--Nested Repeater would go here for all the children info for each "Group"--%>
</ItemTemplate>
</asp:Repeater>
Using DISTINCT in my SQL to just retrieve "Group" leaves me with the proper groups without repeats and I guess I could just instead set the groups in labels and then later make repeaters for each specific label... This seems terrible when I may later update editableData back to the database.
What I really want I guess is at least a link to a walkthrough that explains how repeaters work along with Eval() and datasources. I mean, code to do everything I need to complete this first step in my project would be perfect ;P But I also want to be able to understand these better as I am probably going to be using them often in the near future.
I once encountered the same issue where I was to sort the data by group and I had to display the common items in a grouped segment.
There are of-course multiple ways of how you retrieve data, for example, you can get Distinct Group Names and bind it to the repeater and then on ItemDataBound event you can execute and get other elements like this:
<asp:Repeater runat="server" ID="rptrGroups" OnItemDataBound="rptrGroups_ItemDataBound">
<ItemTemplate>
<asp:Label runat="server" ID="lblGroupName" Text='<%# Eval("GroupName") %>' />
<asp:GridView runat="server" ID="gv">
</asp:GridView>
</ItemTemplate>
</asp:Repeater>
protected void rptrGroups_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
{
var lblGroupName = (Label)e.Item.FindControl("lblGroupName");
GridView gv = (GridView)e.Item.FindControl("table");
var dataTable = FetchDataWithGroupName(lblGroupName.Text); // Method that fetches data with groupname.
gv.DataSource = dataTable;
gv.DataBind();
}
}
This is not a recommended way because it goes to database, runs query, and then fetches data for each item (if you are fetching this data from db). If you have thousands of Groups then it will make db calls for thousands of times which is a bad thing.
The second solution is, you design a model and feed a custom model that will do the job. Let me explain it by a sample model:
public class GroupedModel
{
public string GroupName {get; set;}
public List<NestedData> TableData {get; set;}
}
public class NestedData
{
public string Id {get; set;}
// Your columns here...
}
Then query and initialize list of GroupedModel class then feed it to the repeater. Let me do it with some dummy data.
var tableData = new List<NestedData>();
var nestedData1 = new NestedData { Id = "1" };
var nestedData2 = new NestedData { Id = "2" };
tableData.Add(nestedData1);
tableData.Add(nestedData2);
var groupedModel = new GroupedModel
{
GroupName = "Group1",
TableData = tableData
};
var listGroupedModel = new List<GroupedModel>();
listGroupedModel.Add(groupedModel);
rptrGroups.DataSource = listGroupedModel;
Then modify the markup like this:
<asp:Repeater runat="server" ID="rptrGroups">
<ItemTemplate>
<asp:Label runat="server" ID="lblGroupName" Text='<%# Eval("GroupName") %>' />
<asp:GridView runat="server" ID="gv" DataSource='<%# ((GroupedModel)Container.DataItem).TableData %>'>
</asp:GridView>
</ItemTemplate>
</asp:Repeater>
I find that just using a gridview or list view works rather nice. However, DO NOT attempt to use the grouping feature - as it is for placing items across the page, not down.
Lets make this really simple!
Ok, so I have a list of Hotels, but I want to group by city.
So, you build a query like this:
Dim strSQL As String =
"SELECT ID, FirstName, LastName, HotelName, City FROM tblHotels ORDER BY City, HotelName"
GridView1.DataSource = Myrst(strSQL)
GridView1.DataBind()
Ok, so that fills out our grid view. We get this:
So far, two lines of code!
But, we want to group by City.
So at the forms class level, add simple var:
Public Class HotelGroupGrid
Inherits System.Web.UI.Page
Dim LastCity As String <----- this one
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LastCity = ""
Call LoadGrid()
End If
End Sub
Ok, so now on the data item bind event, simply add a NEW row.
The code looks like this:
If e.Row.RowType = DataControlRowType.DataRow Then
' if grouping = 1 then create a new row!
Dim gvRow As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
If gvRow("City") <> LastCity Then
LastCity = gvRow("City")
' insert a new row for grouping header
Dim MyRow As New GridViewRow(-1, -1, DataControlRowType.DataRow, DataControlRowState.Normal)
Dim MyCel As New TableCell()
'MyCel.Width = Unit.Percentage(100)
Dim MyTable As Table = e.Row.Parent
MyCel.ColumnSpan = MyTable.Rows(0).Controls.Count
Dim MyLable As New Label
MyLable.Text = "<h2>" & gvRow("City") & "</h2>"
MyCel.Controls.Add(MyLable)
MyRow.Cells.Add(MyCel)
MyTable.Rows.AddAt(MyTable.Rows.Count - 1, MyRow)
End If
End If
Now, above is a "bit" of a chunk to chew on - but still not a lot of code.
So, now when we run above, we get this:
Our grid view markup looks like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="City" HeaderText="City" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="FirstName" HeaderText="FirstName" SortExpression="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" SortExpression="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" SortExpression="HotelName" />
</Columns>
</asp:GridView>
So, not too bad.
If you decide to use a listview? Then the code becomes quite a bit less, but the markup for listview is quite a handfull.
All we do is create a row that is our heading, and now show, or hide that row based on the start of new grouping.
So, if one decides to use a list view? Then we get this:
(I assume you use the databind wizards - your not possibly typing in the markup by hand - right? - saving world poverty here)
So, for a list view (and I think the list view is BETTER, since the layout options for that heading row is wide open to any kind markup and extra controls you dream up.
So, the markup (generated - and then chopped out the fat) is this:
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ID">
<EmptyDataTemplate>
<table runat="server" style="">
<tr><td>No data was returned.</td></tr>
</table>
</EmptyDataTemplate>
<ItemTemplate>
<tr id="GroupHeading" runat="server" style="display:none">
<td colspan="4">
<h2><asp:Label ID="City" runat="server" Text='<%# Eval("City") %>' /></h2>
</td>
</tr>
<tr>
<td><asp:Label ID="IDLabel" runat="server" Text='<%# Eval("ID") %>' /></td>
<td><asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstName") %>' /></td>
<td><asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>' /></td>
<td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table id="itemPlaceholderContainer" runat="server" border="0" style="">
<tr runat="server">
<th runat="server">ID</th>
<th runat="server">FirstName</th>
<th runat="server">LastName</th>
<th runat="server">HotelName</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
Now no question that the listview spits out a lot more markup - but we now have a full row for the heading. So we get this:
But, now our code simply will hide or show that "extra" row we have in the marketup.
And it quite simple now:
If e.Item.GetType = GetType(ListViewDataItem) Then
Dim MyRow As HtmlTableRow = e.Item.FindControl("GroupHeading")
Dim lblCity As Label = MyRow.FindControl("City")
If lblCity.Text <> LastCity Then
LastCity = lblCity.Text
' Hide/show group heading
MyRow.Style("display") = "normal"
Else
MyRow.Style("display") = "none"
End If
End If
So the trick in most cases is to simply layout that extra row item, and then on the item data bound event you simply hide or show that heading part.

Use ListView control to display data but join a reference table

I'm really new to ASP.NET and I've looked at countless tutorials trying to figure this out but can't seem to get my head around it. I can successfully output records from tbProject using ListView and the Entity Framework but instead of the refDepartmentID, I want to display refDepartmentValue from the refDepartment table. Here is a quick table structure.
tbProject
-ProjectID
-refDepartmentID
-ProjectName
refDepartment
-refDepartmentID
-refDeparmentValue
I can write this in SQL no problem with a JOIN but I don't know where I'd put it. I've played around with LINQ a bit and it seems like this is how I'm going to accomplish this. Maybe write the LINQ in the code behind file then bind it to the ListView control, maybe?
Here's the ListView control:
<asp:ListView runat="server"
DataSourceID="EntityDataSource1">
<ItemTemplate>
<tr style="">
<td>
<asp:Label ID="ProjectIDLabel" runat="server" Text='<%# Eval("ProjectID") %>' />
</td>
<td>
<asp:Label ID="refDepartmentIDLabel" runat="server"
Text='<%# Eval("refDepartmentID") %>' />
</td>
</tr>
</ItemTemplate>
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table ID="itemPlaceholderContainer" runat="server" border="0" style="">
<tr runat="server" style="">
<th runat="server">
ProjectID</th>
<th runat="server">
refDepartmentID</th>
</tr>
<tr ID="itemPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server" style="">
</td>
</tr>
</table>
</LayoutTemplate>
</asp:ListView>
Here's how I'm using the EF to populate a dropdownlist so you can at least refer to how things are named.
// populates Departments dropdownlist
using (dbOrganizationEntities1 myEntities = new dbOrganizationEntities1())
{
var allDepartments = from refDepartments in myEntities.refDepartments
select refDepartments;
ddlDepartments.DataSource = allDepartments;
ddlDepartments.DataValueField = "refDepartmentID";
ddlDepartments.DataTextField = "refDepartmentValue";
ddlDepartments.DataBind();
}
Any help would be appreciated. Thanks!
Disclaimer, I did this in my head without Visual Studio, so it might have a minor syntax error. Let me know if it does.
You need to do two things, First you must join your tbProject to refDepartments Entites using an inner (or outer) join as needed, depending on your desired behavior. One you have the two tables joined in LINQ, you want to create a new anonymous class using "select new" operator which creates it. The members of this new class will be created based on the datatypes of the Entities they are selected from.
using (dbOrganizationEntities1 myEntities = new dbOrganizationEntities1())
{
var allDepartments = (from tbProject in myEntities.tbProjects
// inner join to department lookup table
from refDepartments in myEntities.refDepartments.Where(x=>x.refDepartmentID == tbProject.refDepartmentID) // to do a left join instead of an inner, append .DefaultIfEmpty() after this where clause
// select new anon type
select new {
refDepartmentID = tbProject.refDepartmentID,
ProjectName = tbProject.ProjectName,
refDepartmentValue = refDepartments.refDepartmentValue,
}).ToList(); // I chose to turn the result into a list to demonstrate something below, you can leave it as an enumerable.
// you can access the properties of the anon type like so
System.Diagnostics.Debug.Print(allDepartments[0].refDepartmentID);
System.Diagnostics.Debug.Print(allDepartments[0].refDepartmentValue);
// bind to your listview, make sure control name is accurate and ItemTemplates are defined for each data column.
MyListView.DataSource = allDepartments;
MyListView.DataBind();
}

Build Listview from Code behind

I have a large table that can have many null, empty or false columns. I only want to show the columns that are worth showing.
Here is a sample of the query and how I am trying to build up the listview:
var query = (from q in db.tblIncidents
where q.Id == searchQuery
select new
{
q.victim,
q.reportedByVictimPostCode
}).ToList();
lst_Results.DataSource = query;
lst_Results.DataBind();
foreach (var colitem in query)
{
if (!colitem.victim == false)
{
** Help required here please **
lst_Results.Items.Add(new ListViewDataItem(0,1));
}
}
I did start off building my list view on the aspx page, but realised that the result would be lots of empty fields and a waste of time for the user seeing nothing if the user hadn't entered any thing.
What I want to do is achieve this but in the code behind by querying if there is a result to display.
<ItemTemplate>
<tr>
<td>Incident Id:</td>
<td>
<asp:Label ID="lbl_CustomerId" runat="server" Text='<%# Eval("Id") %>' />
</td>
</tr>
<tr>
<td>Reported by the Victim:</td>
<td>
<asp:Label ID="lbl_victim" runat="server" Text='<%# Eval("victim") %>' />
</td>
</tr>
</ItemTemplate>
Would I use something like so?
lst_Results.InsertItem.DataItem(colitem.victim);
Which I get the error method delegate or event expected?
Does it know to insert into the listItem template?
I have a layout template with the itemPlaceholder. The listview works ok just want to target it from code behind.

Once clicking the select button of a row, a gridview appears between that row and the rest of the gridview. Possible?

I'd like to have the user click the select button of, lets say, the 250th row of a 400 row gridview. When they click that, then another gridview that's 3x12 appears below that row, then the 150 other rows appear below that. Is this at all possible? I guess I could create a whole other div that'll have three gridviews that output depending on being <= and > the index of the selected row.
It starts as:
Gridview rows 1-400
Then after row 350 is selected is it:
Gridview rows 1-350
Gridview of row 350 info
Gridview rows 351-400.
It's definitely possible, but I would use a ListView or DataList as your parent container instead, because with a GridView, you'll have to put the child list in a column, which will look ugly. This should put you on the right path:
<asp:ListView ID="lstOuterList" runat="server" DataKeyNames="ID, OtherColumn">
<LayoutTemplate>
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><asp:LinkButton ID="LinkButton1" runat="server" Text="Expand" OnCommand="LinkButton1_Command" CommandArgument='<%#Container.DisplayItemIndex%>'></asp:LinkButton></td>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
<asp:PlaceHolder ID="plcInnerList" runat="server">
<asp:ListView ID="lstInnerList" runat="server" Width="100%">
<LayoutTemplate>
<tr>
<td colspan="4">
<div style="padding:20px;background-color:#fffeee;">
<table width="100%">
<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />
</table>
</div>
</td>
</tr>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td><%#Eval("Value")%></td>
<td><%#Eval("OtherValue")%></td>
<td><%#Eval("OtherOtherValue")%></td>
</tr>
</ItemTemplate>
</asp:ListView>
</asp:PlaceHolder>
</ItemTemplate>
</asp:ListView>
And when the user clicks the LinkButton/Button in DataList1, do something like this:
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
//pass index of item in command argument
var itemIndex = Convert.ToInt32(e.CommandArgument);
//find the pnlChildView control
var innerPlaceHolder = lstOuterList.Items[itemIndex].FindControl("plcInnerList") as PlaceHolder;
if (innerPlaceHolder != null)
{
innerPlaceHolder.Visible = !innerPlaceHolder.Visible;
if (innerPlaceholder.Visible)
{
var innerList = innerPlaceHolder.FindControl("lstInnerList") as ListView;
if (innerList != null)
{
//the id to retrieve data for the inner list
int keyValue = (int)lstOuterList.DataKeys[itemIndex]["ID"];
//bind the list using DataList1 data key value
innerList.DataSource = new DataTable("DataSource"); //your datasource
innerList.DataBind();
}
}
}
}
one way is:
on the rowcommand of the main grid:
create c# code for the grid will be inside GridView grd = new GridView();
bind this instance like any other grid
add on the controls from the main grid current line, should be something like
e.Cells[0].Controls.Add(grd);
I don't have VS here right now but I guess you could get the idea, I use this approach all the time

Adding String Array to listView Row Control C# asp.net

This is my first attempt at asp.net and webforms, windowsforms, all of it. I originally populated data in a listbox, but I could only get one column and thought the listView sounded like it would do what I wanted.
The most promising solution I found was this:
DataSet listData = new DataSet();
CancellationsControls cancelCtrl = new CancellationsControls();
listData = cancelCtrl.GetScheduledReleaseDataSet();
DataTable dtable = listData.Tables[0];
scheduledReleasesTag.Items.Clear();
foreach (DataRow row in dtable.Rows)
{
string[] ar = Array.ConvertAll(row.ItemArray, p => p.ToString());
scheduledReleasesTag.Items.Add(new ListViewDataItem(ar));
}
The dtable is a custom table of a query joining a number of tables.
in the foreach loop the ar string array succesfully shows the colums of data that I want, but the ListViewDataItem requires two int arguments instead of a string array like the example I pulled this from.
I've tried to figure out more about how the listView control works, but this is as close as I have been able to get to getting anything. Any help with explanations would be very appreciated.
Thank you :)
I'm pretty beginner in asp, but to bind ListView control with data, smth like this should work:
DataSet listData = new DataSet();
CancellationsControls cancelCtrl = new CancellationsControls();
listData = cancelCtrl.GetScheduledReleaseDataSet();
DataTable dtable = listData.Tables[0];
ListView1.DataSource = dtable;
ListView1.DataBind();
Now we have to create an ItemTemplate. Your ListView control should look like:
<asp:ListView ID="ListView1" runat="server">
<ItemTemplate>
<tr id="Tr1" class="item" runat="server">
<td>
<asp:Label ID="column_name" runat="server" Text='<%# Eval("column_name") %>' />
</td>
</tr>
<tr id="Tr2" class="item" runat="server">
<td>
<asp:Label ID="another_column_name" runat="server" Text='<%# Eval("another_column_name") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
Just replace markers(column_name,another_column_name) with names of columns, that contains data you want to display. This template displays pairs of rows values from two columns one by one.

Categories