I have a page that includes a GridView in it. That GridView is paged with 10 items at a time. Normally, I want the user to select the item from the GridView and populate the FormView. This works well.
I also want to support a query parameter ?ID=n where the page will load the specified item.
How do I tell the DataGrid or the data source which item to set as the data context?
I want the DataGrid to go to the proper page and select the item, showing the specified item in the FormView.
I can't figure out how to do this other than limiting the data source to the specific item, which is confusing to the user.
Any thoughts?
If you set the DataKey field of the GridView to contain the primary key, there is this CodeProject article on how to set the selected index of a gridview, based on the key value of the record, using an extension method:
public static void SetRowValueValueByKey(this GridView GridView, string DataKeyValue)
{
int intSelectedIndex = 0;
int intPageIndex = 0;
int intGridViewPages = GridView.PageCount;
// Loop thru each page in the GridView
for (int intPage = 0; intPage < intGridViewPages; intPage++)
{
// Set the current GridView page
GridView.PageIndex = intPage;
// Bind the GridView to the current page
GridView.DataBind();
// Loop thru each DataKey in the GridView
for (int i = 0; i < GridView.DataKeys.Count; i++)
{
if (Convert.ToString(GridView.DataKeys[i].Value) == DataKeyValue)
{
// If it is a match set the variables and exit
intSelectedIndex = i;
intPageIndex = intPage;
break;
}
}
}
// Set the GridView to the values found
GridView.PageIndex = intPageIndex;
GridView.SelectedIndex = intSelectedIndex;
GridView.DataBind();
}
The correct solution for this is going to vary a bit depending on how you are actually pulling the data from the database. But the process is pretty much the same.
- Get your data from your database to bind to the grid.
- Lookup the item that should be displayed. Find out what row it is in
- Now, determine what page should be selected, and what row on that page should be selected.
- Set the CurrentPageIndex and bind the grid. now you can set the selected item
Now, the kicker here is step 1 and 2. if you are paging the data at the SQL level, you will need to get another stored procedure/database call to determine the "row id" of the selected item. Otherwise, if you are loading to a object collection, or a dataset, you can loop through and find the item. Keeping a row counter if you really must.
Not elegant, but honestly there isn't an "elegant" way of doing this.
@Brian if I'm correctly understanding your question you mean that you have everything wired up it user clicks on a row when the page is showing. You want that if somebody types the URL of page directly in browser and appends ?id=x to it, you should direct him to relevant page, select relevant row and populate FormView based on selected record.
Well if this is the case I've made something, but let me warn before hand it is not very elegant and its 2:30 AM here so please don't laugh.
Assumption:- In presented solution the DataKeyNames field is set to Primary Key of the source table. The rows fetched are sorted by this key. I'm using SubSonic 3 for talking to SQL Server 2005 Express DB (coincidently this is my first SS3 project, very busy at office to try it).
The table definition is as follows:
Create Table StudentsTable
( EnrolmentNumber int not null identity primary key,
StudentName nvarchar(50) not null)
The aspx:
<asp:GridView ID="gvStudents" runat="server" AllowPaging="True" PageSize="3"
OnSelectedIndexChanged="GridRowChanged" OnPageIndexChanging="GridPageChanging"
DataKeyNames="EnrolmentNumber">
<RowStyle BackColor="LightBlue" />
<AlternatingRowStyle BackColor="LightCoral" />
<Columns>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server"
CommandName="Select" Text="Select"></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
<SelectedRowStyle BackColor="Red" BorderColor="Yellow" />
</asp:GridView>
<asp:FormView ID="fvSubjects" runat="server" AllowPaging="false"
Caption="Student" CaptionAlign="Left">
<ItemTemplate>
<table>
<tr>
<td>Enrolment Number</td>
<td><asp:Label ID="lblEN" runat="server"
Text=<%# Eval("EnrolmentNumber") %> /></td>
</tr>
<tr>
<td>Student Name</td>
<td><asp:Label ID="lblName" runat="server"
Text=<%# Eval("StudentName") %> /></td>
</tr>
</table>
</ItemTemplate>
</asp:FormView>
C# Code (Hold your laughs):
private IList<StudentsTable> students;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
LoadData();
CheckQueryString(students);
}
}
private void LoadData()
{
students = StudentsTable.All().ToList();
gvStudents.DataSource = students;
gvStudents.DataBind();
}
private void CheckQueryString(IList<StudentsTable> students)
{
if (!Request.QueryString.HasKeys() ||
string.IsNullOrEmpty(Request.QueryString["erno"]))
{
return;
}
var erno = Request.QueryString["erno"];
int key;
if (!int.TryParse(erno, out key))
return;
for (var i = 0; i < students.Count; i++)
{
if (students[i].EnrolmentNumber == key)
{
SetPageSize(students, i);
break;
}
}
}
private void SetPageSize(IList<StudentsTable> students, int i)
{
var ps = gvStudents.PageSize;
var cp = i / ps;
var ridx = i - ps - 1;
var pageEvent = new GridViewPageEventArgs(cp);
GridPageChanging(null, pageEvent);
gvStudents.SelectedIndex = ridx;
GridRowChanged(null, EventArgs.Empty);
}
protected void GridRowChanged(object sender, EventArgs e)
{
var rIdx = gvStudents.SelectedIndex;
if (rIdx < 0) return;
var key = gvStudents.DataKeys[rIdx];
var lst= StudentsTable.Find(x => x.EnrolmentNumber == (int)key.Value);
SetFormView(lst);
}
private void SetFormView(IList<StudentsTable> student)
{
fvSubjects.DataSource = student;
fvSubjects.DataBind();
}
protected void GridPageChanging(object sender, GridViewPageEventArgs e)
{
var p = e.NewPageIndex;
if (p > gvStudents.PageCount)
p = gvStudents.PageCount - 1;
gvStudents.PageIndex = p;
LoadData();
}
PS:- It is failing if you put id of last record.
EDIT:- Here is link to Project
The Data Access tutorials on ASP.NET touch on aspects of your question. It's been a while for me, but I think that the last part of this particular tutorial maybe the closest to what you need:
http://www.asp.net/learn/data-access/tutorial-10-vb.aspx
Just turn on paging for the GridView and everything should just work.