Gridview from checkboxlist - c#

I have a dynamically created Checkboxlist ( I am using Dynamic Data and I am talking about the Many-to-many_edit.aspx ).
I have like 20 000+ item added in my Checkboxlist and I need pagination for this.
I thought binding this checkboxlist to a gridview would do the trick? How can I do this ?
EDIT: I've read a lot about this subject but I couldn't find anything good . When I try to put Checkboxlist's source in my GridView.DatSource it throws OutOfMemory exception
EDIT2: I am trying something like this, but now, because my checkboxlist it's inside the gridview I don't know how to populate it anymore
code sample:
asp:GridView ID="GridView1" runat="server">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBoxList ID="CheckBoxList1" runat="server" RepeatColumns="3" OnDataBound="CheckBoxList1_DataBound" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
EDIT3:
My code aspx.cs
public partial class ManyToMany_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
public void Page_Load(object sender, EventArgs e)
{
// Register for the DataSource's updating event
EntityDataSource ds = (EntityDataSource)this.FindDataSourceControl();
// This field template is used both for Editing and Inserting
ds.Updating += new EventHandler<EntityDataSourceChangingEventArgs>(DataSource_UpdatingOrInserting);
ds.Inserting += new EventHandler<EntityDataSourceChangingEventArgs>(DataSource_UpdatingOrInserting);
}
private void DataSource_UpdatingOrInserting(object sender, EntityDataSourceChangingEventArgs e)
{
MetaTable childTable = ChildrenColumn.ChildTable;
// Comments assume employee/territory for illustration, but the code is generic
// Get the collection of territories for this employee
RelatedEnd entityCollection = (RelatedEnd)Column.EntityTypeProperty.GetValue(e.Entity, null);
// In Edit mode, make sure it's loaded (doesn't make sense in Insert mode)
if (Mode == DataBoundControlMode.Edit && !entityCollection.IsLoaded)
{
entityCollection.Load();
}
// Get an IList from it (i.e. the list of territories for the current employee)
// REVIEW: we should be using EntityCollection directly, but EF doesn't have a
// non generic type for it. They will add this in vnext
IList entityList = ((IListSource)entityCollection).GetList();
// Go through all the territories (not just those for this employee)
foreach (object childEntity in childTable.GetQuery(e.Context))
{
// Check if the employee currently has this territory
bool isCurrentlyInList = entityList.Contains(childEntity);
// Find the checkbox for this territory, which gives us the new state
string pkString = childTable.GetPrimaryKeyString(childEntity);
ListItem listItem = CheckBoxList1.Items.FindByValue(pkString);
if (listItem == null)
continue;
// If the states differs, make the appropriate add/remove change
if (listItem.Selected)
{
if (!isCurrentlyInList)
entityList.Add(childEntity);
}
else
{
if (isCurrentlyInList)
entityList.Remove(childEntity);
}
}
}
protected void CheckBoxList1_DataBound(object sender, EventArgs e)
{
MetaTable childTable = ChildrenColumn.ChildTable;
var a = childTable.CreateContext();
var dataSource = childTable.GetQuery().AsQueryable();
var Context = new testEntities();
var daZtaSource = Context.GetType();
GridView1.DataSource = dataSource;
// Comments assume employee/territory for illustration, but the code is generic
IList entityList = null;
ObjectContext objectContext = null;
if (Mode == DataBoundControlMode.Edit)
{
object entity;
ICustomTypeDescriptor rowDescriptor = Row as ICustomTypeDescriptor;
if (rowDescriptor != null)
{
// Get the real entity from the wrapper
entity = rowDescriptor.GetPropertyOwner(null);
}
else
{
entity = Row;
}
// Get the collection of territories for this employee and make sure it's loaded
RelatedEnd entityCollection = Column.EntityTypeProperty.GetValue(entity, null) as RelatedEnd;
if (entityCollection == null)
{
throw new InvalidOperationException(String.Format("The ManyToMany template does not support the collection type of the '{0}' column on the '{1}' table.", Column.Name, Table.Name));
}
if (!entityCollection.IsLoaded)
{
entityCollection.Load();
}
// Get an IList from it (i.e. the list of territories for the current employee)
// REVIEW: we should be using EntityCollection directly, but EF doesn't have a
// non generic type for it. They will add this in vnext
entityList =((IListSource)entityCollection).GetList();
// Get the current ObjectContext
// REVIEW: this is quite a dirty way of doing this. Look for better alternative
ObjectQuery objectQuery = (ObjectQuery)entityCollection.GetType().GetMethod(
"CreateSourceQuery").Invoke(entityCollection, null);
objectContext = objectQuery.Context;
}
// Go through all the territories (not just those for this employee)
foreach (object childEntity in childTable.GetQuery(objectContext))
{
MetaTable actualTable = MetaTable.GetTable(childEntity.GetType());
// Create a checkbox for it
ListItem listItem = new ListItem(
actualTable.GetDisplayString(childEntity),
actualTable.GetPrimaryKeyString(childEntity));
// Make it selected if the current employee has that territory
if (Mode == DataBoundControlMode.Edit)
{
listItem.Selected = entityList.Contains(childEntity);
}
CheckBoxList1.Items.Add(listItem);
}
}
public override Control DataControl
{
get
{
return CheckBoxList1;
}
}
}
My code: Aspx
<%# Control Language="C#" CodeFile="ManyToMany_Edit.ascx.cs" Inherits="ManyToMany_EditField" %>
<asp:CheckBoxList ID="CheckBoxList1" runat="server" RepeatColumns="3" OnDataBound="CheckBoxList1_DataBound" />

Why do you want a checkbox list inside a gridview ? I think you may replace your checkboxlist by a checkbox and add a column with the data you want to display.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" showheader="false" allowpaging="true">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="CheckBoxList1" runat="server" checked='<%# Eval("myColumn")%>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="cbxLabel" />
</Columns>
</asp:GridView>
You will have the pagination that you are wanting.
And also don't forget during the page changing to save the checked checkboxes and to restore it also.
To Paginate your result please take a look at this thread:
How to paginate a gridview and SQL custom query with ROW_NUMBER

Related

Updating a Data Bound GridView on Button Click

So I have a .aspx page that is bound to some data. I can run a LINQ query and return it as an IQueryable object in the SelectMethod for the GridView control, and it will populate fine. What I am trying to do is populate the GridView based upon a selection from a ListBox control. Since the data is bound, I can't set the DataSource equal to the query. I could maybe figure out a way to re-use the SelectMethod based on a public string (which would in turn be based off the ListBox selection), but that would be pretty ugly.
Here is the gridview control on my .aspx page:
<asp:GridView runat="server" ID="employeesGrid"
ItemType="Foo.Models.Employee" DataKeyNames="EmployeeID"
SelectMethod="employeeGrid_GetData"
AutoGenerateColumns="false">
<Columns>
<asp:DynamicField DataField="EmployeeID" />
<asp:DynamicField DataField="FirstName" />
<asp:DynamicField DataField="LastName" />
<asp:DynamicField DataField="CompanyName" />
</Columns>
</asp:GridView>
And here is my SelectMethod in the .cs:
public IQueryable<Employee> employeeGrid_GetData()
{
FooContext db = new FooContext();
var query = db.Employees.Where(e => e.CompanyName == "NameOfCompany");
return query;
}
That populates the GridView just fine on load, but it doesn't do much for me with updating on click.
And here is the button click method that I've tried but doesn't work. I get an error about not being able to use DataSource or DataSourceId when the GridView is bound to a data model:
public void btn_RequestEmployees_Click(object sender, EventArgs e)
{
string currentlySelectedEmployer = lstbxEmployers.SelectedValue.ToString();
FooContext db = new FooContext();
var query = db.Employees.Where(employee => employee.CompanyName == currentlySelectedEmployer);
employeesGrid.DataSource = query;
DataBind();
}
Any advice? Thanks.
Try it like this:
public IQueryable<Employee> employeeGrid_GetData()
{
string currentlySelectedEmployer = lstbxEmployers.SelectedValue.ToString();
FooContext db = new FooContext();
var query = db.Employees.Where(employee => employee.CompanyName == currentlySelectedEmployer);
return query;
}

data pager in listview Issue

I have a listview where in I placed datapager as follows.
I am using SQl datasource and binding the records to ListView.
asp:ListView runat="server" ID="ListView1" DataKeyNames="ProductId,GameName" DataSourceID="GameTable" OnItemCommand="On_Select_Item"
and datapager in the LayoutTemplate
And in the item template I am placing a button, when clicked it calls a method where i am trying to fetch DatakeyName values. It is working fine in first page when pager is given, However when moved to other page in the pager, it is throwing me an exception.
Here is the button click code,
protected void On_Select_Item(object sender, ListViewCommandEventArgs e)
{
if (String.Equals(e.CommandName, "AddtoCart"))
{
//checks if the user is logged in
if (User.Identity.IsAuthenticated)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
DropDownList dl = e.Item.FindControl("DropDownList") as DropDownList;
String val="";
if (dl != null)
{
val = dl.SelectedValue; //Get the selected value from DropDownList
}
String price = Convert.ToString(e.CommandArgument).Trim(); //Get the price for the selected game.
-------------Exception is thrown at below line ---------
string ProductId =
ListView1.DataKeys[dataItem.DataItemIndex]["ProductId"].ToString(); //Product Id for the selected game.
string GameName = ListView1.DataKeys[dataItem.DataItemIndex]["GameName"].ToString(); //gamename
...............................
.............................
}
Define a grid first (you can change the control name to listView but the implementation is the same )
<asp:GridView runat="server" ID="grdResult"
CellPadding="2"
OnPageIndexChanging="grdResult_PageIndexChanging"
GridLines="None"
Width="100%"
AllowSorting="True"
AllowPaging="True"
Then in the bottom define a data source
<asp:SqlDataSource ID="sqlGridData" runat="server"></asp:SqlDataSource>
now in the code behind load your sqlGridData control with data (it accepts many parameters like datatable, odbcrecordset you can use .provider property mentioned here http://tinyurl.com/bllyjsz ) if you have static data them you even mention at the design time (as done here http://tinyurl.com/c8b6mbh)
private void BindDataGrid()
{
sqlGridData.Provider = dataReader;
grdResult.DataSourceID = "xmlGridData";
//grdResult.PageIndex = 0;
}
Try this and do let me know if you have any query.

how to find datagrid row in asp.net 2.0 C#

I am using dot net 2.0 and c#.
I have a requirement where i have to find rows of datagrid and pass then as an argument in a function, could you please provide me code for findind a row in datagird. Thanks
You can try with ItemDataBound event on your datagrid
void Item_Bound(Object sender, DataGridItemEventArgs e)
{
if((e.Item.ItemType == ListItemType.Item) ||
(e.Item.ItemType == ListItemType.AlternatingItem))
{
var control = (Label)e.Item.FindControl("YourLabel");
control.Text="pass your value";
}
}
<asp:DataGrid id="DataGrid1"
runat="server"
AutoGenerateColumns="False" OnItemDataBound="Item_Bound">
<Columns>
<asp:TemplateColumn HeaderText="Sample">
<ItemTemplate>
<asp:Label id="YourLabel" runat="server"/>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
You could loop your gridview / datagrid rows and do whatever you want when some criteria matches what you are looking for.
foreach (GridViewRow gvr in gvDemo.Rows) {
if (gvr.DataItem != null) {
//depending on how or what you want to find
//check a key
if (gvDemo.DataKeys[gvr.RowIndex].Values[0] == "xx") {
}
//or a field value
if (gvr.Cells[0].ToString() == "123") {
}
//or first cast your row data item back to a known class
CarBrand carBrand = (CarBrand)gvr.DataItem;
if (carBrand.Name == "Porsche") {
//
}
//or pass the whole row to whatever function
if (xx == yy) {
DoSomething(gvr);
}
}
}
You just put the datagrid to the ItemDataBound and and calling the Event ItemDataBound_click
Write this
string rownumber = e.Item.FindControl("your id for the label") As Label
and use after converting the equivalent data type you use this as a parameter.

Passing two values through CommandArgument and splitting it

I'm using the commandArgument property of the LinkButton ( Which is wrapped inside a repeater ) to pass two values -as one string- to a second repeater then I try to split them into two values, So I could use them as parameters in my ADO.NET Code (SqlCommand Parameters)....after testing my queries don't return any results but If I passed fixed values for the parameter or change the source of the parameter (just for test from a textbox or querystring or something) I get my results, so I think the problem is in splitting.
I Conduct some arugment values from the ArgumentCommand property of the LinkButton -which is wrapped inside a repeater:
<ItemTemplate>
<asp:LinkButton id="sort_lnkbtn" Text='<%# Eval("value")%>'
CommandArgument='<%#string.Format("{0}|{1}",Eval("arrange_by_id"),Eval("value"))%>' runat="server">
</asp:LinkButton>
</ItemTemplate>
Then I receive these values and cut them into two pieces of information:
string sortByAndArrangeBy = (e.CommandArgument).ToString();
char[] separator = { '|' };
string[] sortByAndArrangeByArray = sortByAndArrangeBy.Split(separator);
Now the ado.net code uses this values as a
using (SqlConnection cn1 = new SqlConnection(ConfigurationManager.ConnectionStrings["testConnectionString"].ConnectionString))
{
using (SqlCommand cm1 = new SqlCommand("SELECT [name] FROM brands WHERE (name like #SearchString + '%' )", cn1))
{
cm1.Parameters.Add("#SearchString", System.Data.SqlDbType.Char);
cm1.Parameters["#SearchString"].Value = sortByAndArrangeByArray[1];
cn1.Open();
using (SqlDataReader dr1 = cm1.ExecuteReader())
{
List_rpt.DataSource = dr1;
List_rpt.DataBind();
}
}
}
Here is a simple solution:
Wrap your item template for the repeater in a control. The control will have the same markup as your item template without the bindings:
Control Markup:
<div>
<asp:LinkButton ID="LnkBtnSort" runat="server" Text="Sort" OnClick="LnkBtnSort_Clicked"/>
</div>
Control Code:
public class SomeControl
{
public event EventHandler Click;
public string ArrangeById
{
set { ViewState["byid"] = value; }
get { return ViewState["byid"].ToString(); }
}
public string Value
{
set { ViewState["val"] = value; }
get { return ViewState["val"].ToString(); }
}
protected void LnkBtnSort_Clicked(object sender, EventArgs e)
{
if( Click != null )
{
this.Click(this, EventArgs.Empty);
}
}
}
So now in the repeater all you have to do is bind an instance of that control to the Container.DataItem:
<ItemTemplate>
<ctrl:SomeControl
ID="someControl"
runat="server"
OnClick="SomeControl_Clicked"
ArrangeById='<%# Eval("arrange_by_id") %>'
Value='<%# Eval("value") %>' />
</ItemTemplate>
The page/control that has the repeater will have one simple method:
protected void SomeControl_Clicked(object sender, EventArgs e)
{
//Here cast the sender to the type of control you made:
SomeControl ctrl = (SomeControl)sender;
string byId = ctrl.ArrangeById;
string val = ctrl.Value;
}
Note: this code may not be 100% correct but it illustrates the point. The flow is simple - the control binds its public properties to whatever you need to bind. When the link is clicked (inside your control) the control doesn't propagate this event to the page. Instead it fires its own event (Click) thus sending a signal to the page that an event occured. however by doing so, it changes the source of the event to itself instead of the actual link button. The page handles the event and everyone is happy.
This way you don't have to care what the CommandArgument is... If this comes up empty, it means that either your data source is empty... or something else happened in the code.

Gridview - Reference to a new column

I have a gridview which takes in data from 3 tables.
And this gridview also have an additional column called "Role" which is not included in the database.
Currently, without adding any logic but simply using the findcontrol to the label, "Role", i can show out "ML"
But, when I add in the logic, it did not appear at all.
In any case, does anyone knows how to insert "ML" into the "Role" column which is not found in the database but is reference from another column found in the database.
This is the codes used to display the "ML" in the role column.
protected void gridAMDisplay_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//find the Label control using FindControl and set its Text on some column value
DataRowView row = (DataRowView)e.Row.DataItem;
if (!DBNull.Value.Equals(row["ModuleLeader"]))
{
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
Label lbl = e.Row.FindControl("lblRole") as Label;
if (lbl != null)
{
lbl.Text = "ML";
}
}
}
}
}
This part of the code when comment off, the ML can be displayed in the role column, otherwise, nothing is displayed.
Therefore, i feel that the findcontrol part works. BUT, referencing does not works.
if (row["ModuleLeader"].ToString() == "ModuleStr")
{
As i mentioned, the role column was not included in any of the tables in the DB.
Therefore, i added in this codes.
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text="" />
</ItemTemplate>
</asp:TemplateField>
But, the problem i have now is, the role column does not reference to the column it is supposed to, which is "Module Leaders"
You reference the DataItem, which cannot be used in DataBound, you should use OnDataBinding to implement this.
It seems you only want the role column to update to "ML" based on the data present in another column of the same row. Why not just drop it in the XHTML?
<asp:TemplateField HeaderText="Role">
<ItemTemplate>
<asp:Label ID="lblRole" runat="server" Text='<%# GetRoleString(Eval("ModuleLeader"))%>' />
</ItemTemplate>
</asp:TemplateField>
Then in the code behind you could have a method:
string GetRoleString(string moduleLeader)
{
return (moduleLeader == "ModuleStr") ? "ML" : "";
}
This would occur on databinding and would only happen once per row.
The best practice in my humble opinion is to create your own template.
Here is one for your case :
public class NotEmptyValueFromDataTemplate : System.Web.UI.Page, IBindableTemplate
{
protected string p_DataFieldToLookAt;
protected string p_ValueToPlaceInIfNotNull;
protected Literal p_litControl;
public RoleTemplate(string DataFieldToLookAt, string ValueToPlaceInIfNotNull)
{
this.p_DataFieldToLookAt = DataFieldToLookAt;
this.p_ValueToPlaceInIfNotNull = ValueToPlaceInIfNotNull;
}
public virtual void OnInit(object sender, EventArgs e)
{ }
#region IBindableTemplate Members
public System.Collections.Specialized.IOrderedDictionary ExtractValues(Control container)
{
throw new NotImplementedException();
}
#endregion
#region ITemplate Members
public void InstantiateIn(Control container)
{
p_litControl = new Literal();
p_litControl.ID = p_DataFieldToLookAt; /* we don't really care */
p_litControl.Init += new EventHandler(OnInit);
p_litControl.DataBinding += new EventHandler(p_litControl_DataBinding);
container.Controls.Add(p_litControl);
}
void p_litControl_DataBinding(object sender, EventArgs e)
{
var Data = ((GridViewRow)(p_litControl.NamingContainer)).DataItem;
string ValueFromData = Convert.ToString(DataBinder.Eval(Data, p_DataFieldToLookAt));
if(!String.IsNullOrEmpty(ValueFromData))
p_litControl.Text = p_ValueToPlaceInIfNotNull;
}
protected override void OnDataBinding(EventArgs e)
{
base.OnDataBinding(e);
}
#endregion
}
You have then to instantiate each template row :
protected void GridView3_Init(object sender, EventArgs e)
{
((TemplateField)(GridView3.Columns[/* Column Index Here*/])).ItemTemplate = new NotEmptyValueFromDataTemplate("ModuleLeader", "ML");
}
Last, create the template item in the gridview :
<asp:TemplateField HeaderText="Role"></asp:TemplateField>
PS : Code is untested and written out of solution

Categories

Resources