I am going to implement a cascading DropDownList inside a GridView control. My code is given below:
Page:
<asp:GridView ID="GridView1" runat="server" Width="550px"
AutoGenerateColumns="False" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="State">
<ItemTemplate>
<asp:DropDownList ID="DropDownList1"
AutoPostBack="true" runat="server" DataTextField="State" DataValueField="StateID" onselectedindexchanged="DropDownList1_SelectedIndexChanged">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:DropDownList ID="DropDownList2"
AutoPostBack="true" runat="server" DataTextField="City" DataValueField="CityId">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
Code Behind:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl1 = e.Row.FindControl("DropDownList1") as DropDownList;
if (ddl1 != null)
{
using (var context = new ABCEntities())
{
var _state= from u in context.State
select new
{
StateId= u.StateId,
State= u.State
};
ddl1.DataSource =_state.ToList();
ddl1.DataValueField = "StateId";
ddl1.DataTextField = "State";
ddl1.DataBind();
ddl1.Items.Insert(0, new ListItem("--Select--", "0"));
}
}
}
}
protected void DropDownList1_SelectedIndexChanged(object sender, System.EventArgs e)
{
DropDownList ddl1 = (DropDownList)sender;
GridViewRow row = (GridViewRow)ddl1.NamingContainer;
if (row != null)
{
DropDownList ddl2 = (DropDownList)row.FindControl("DropDownList2");
ddl2.DataSource = GetDataForSecondDropDownList(Convert.ToInt32(ddl1.SelectedValue));
ddl2.DataTextField = "CityID";
ddl2.DataValueField = "City";
ddl2.DataBind();
}
}
public IEnumerable<City> GetDataForSecondDropDownList(int ID) //Getting Error
{
using (var context = new ABCEntities())
{
var _city = (from u in context.Cities
where u.StateID == ID
select new City
{
CityID = u.CityID,
City= u.City
}).Distinct();
return _city;
}
}
I am getting an error message : Error: Inconsistent accessibility: return type 'System.Collections.Generic.IEnumerable' is less accessible than method '.......GetDataForSecondDropDownList(int)'
what should i do please help me. Thanks in advance.
The error tells that City class is less accessible. Probably it is private or protected. Make sure you have declared it as public like this:
public class City
{
public int CityID {get;set;}
public string City {get;set;}
}
Related
Data in my GridView inside an UpdatePanel is going out of synch with the database and I can't figure out why. This has resulted in incorrect updates to the database which I have to fix rapidly! Can anyone help?
I have multiple UpdatePanels that have GridViews inside that can be edited by the user. There is a search feature and filter buttons that select queried data from the database and display in the GridView. There is sorting enabled and the "out of synchness" occurs mostly when sorting and then editing a field.
The data comes from a SQL Database. I can update the data directly through OnTextChange option of my TemplateField like this:
<asp:GridView
ID="GridView4"
runat="server"
OnSorting="TaskGridView_Sorting"
AllowSorting="True"
Width="100%" >
<Columns>
<asp:TemplateField SortExpression="name" HeaderText="Name">
<HeaderStyle HorizontalAlign="Left" CssClass="col_name" />
<ItemTemplate>
<asp:TextBox ID="name" AutoPostBack="True" CssClass="col_name" runat="server" Text='<%# Eval("name") %>' Width=180 OnTextChanged="text_change" />
</ItemTemplate>
</asp:TemplateField>
...
I have my gridview inside an UpdatePanel that has these options:
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
...
I have enabled partial rendering like this:
<ajaxToolKit:ToolkitScriptManager EnablePartialRendering="true" runat="server" />
I have buttons that filter the data by requerying the database and displaying just the filtered data like this:
DataGrid_Load(DAL.Search_reg_log(OrgText.Text, searchText, searchCol), "reg");
The gridview gets its data loaded like this:
private void DataGrid_Load(DataTable command, string type)
{
DataTable dataTable = new DataTable();
dataTable = command;
string sortDir = ViewState["SortDirection"] as string;
string sortExp = ViewState["SortExpression"] as string;
if(ViewState["SortExpression"] != null)
{
dataTable = resort(dataTable, sortExp, sortDir);
}
try
{
var query = from c in dataTable.AsEnumerable()
where c.Field<string>("status") == "Invoiced" && c.Field<string>("reg_cat_id") != "Archive"
|| c.Field<string>("status") == "Confirmed" && c.Field<string>("reg_cat_id") != "Archive"
select c ;
if(query.Any()){
DataTable t2 = query.CopyToDataTable();
GridView4.DataSource = t2;
GridView4.DataBind();
} else {
GridView4.DataSource = new DataTable();
GridView4.DataBind();
}
}
catch(Exception e) {
ErrorText.Text = "Caught Exception: " + e;
}
...
I have isolated one cause of the data errors which occurs after sorting a column and then
protected void TaskGridView_Sorting(object sender, GridViewSortEventArgs e)
{
string sortExp = ViewState["SortExpression"] as string;
string sortDir = ViewState["SortDirection"] as string;
if(sortDir == "asc" & sortExp == e.SortExpression.ToString())
ViewState["SortDirection"] = "desc";
else
ViewState["SortDirection"] = "asc";
ViewState["SortExpression"] = e.SortExpression.ToString();
if(searchCol != "" && searchText != "")
DataGrid_Load(DAL.Search_reg_log(OrgText.Text, searchText, searchCol), "reg");
else
DataGrid_Load(DAL.reg_log(HeadText.Text, OrgText.Text), "reg");
UpdatePanels();
}
Here is the resort function:
public static DataTable resort(DataTable dt, string colName, string direction)
{
dt.DefaultView.Sort = colName + " " + direction;
dt = dt.DefaultView.ToTable();
return dt;
}
Please help with some direction of what might be causing this.
It looks like you are having some trouble with GridView and updating them. I will post a complete working example below. Start with that and gradually update that code to fit your own needs, like getting data with var query = from c in dataTable.AsEnumerable(). The important thing is to sort the data every time you (re)bind the GridView data. And I'm not sure what is happening inside resort, but you have to use dt.DefaultView.ToTable(); to save the sorting in the DataTable.
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:GridView ID="GridView1" runat="server"
DataKeyNames="ID" AllowSorting="true"
OnSorting="GridView1_Sorting"
AutoGenerateColumns="false"
AutoGenerateEditButton="true"
OnRowEditing="GridView1_RowEditing"
OnRowCancelingEdit="GridView1_RowCancelingEdit"
OnRowUpdating="GridView1_RowUpdating">
<Columns>
<asp:TemplateField HeaderText="ID" SortExpression="ID">
<ItemTemplate>
<%# Eval("ID") %>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Name" SortExpression="name">
<ItemTemplate>
<%# Eval("name") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text=' <%# Eval("name") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
</ContentTemplate>
</asp:UpdatePanel>
Code behind
protected void Page_Load(object sender, EventArgs e)
{
//bind data in an ispostback check
if (!IsPostBack)
{
DataGrid_Load();
}
}
private void DataGrid_Load()
{
//load the datatable data
DataTable dt = source;
//check if the viewsstate existst
if (ViewState["SortExpression"] != null && ViewState["SortDirection"] != null)
{
//sort the datatable before binding it to the gridview
dt.DefaultView.Sort = ViewState["SortExpression"] + " " + ViewState["SortDirection"];
dt.DefaultView.ToTable();
}
//bind the sorted datatable to the gridvidw
GridView1.DataSource = dt;
GridView1.DataBind();
}
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
//load the previous sorting settigns
string sortExp = ViewState["SortExpression"] as string;
string sortDir = ViewState["SortDirection"] as string;
//reverse the direction if the column is the same as the previous sort
if (sortDir == "asc" & sortExp == e.SortExpression.ToString())
ViewState["SortDirection"] = "desc";
else
ViewState["SortDirection"] = "asc";
//put the current sort column in the viewstate
ViewState["SortExpression"] = e.SortExpression.ToString();
//rebind data
DataGrid_Load();
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
//set the edit index and rebind data
GridView1.EditIndex = e.NewEditIndex;
DataGrid_Load();
}
protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
//reset the edit index and rebind data
GridView1.EditIndex = -1;
DataGrid_Load();
}
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//use findcontrol to locate the textbox in the edit template
TextBox tb = (TextBox)GridView1.Rows[e.RowIndex].FindControl("TextBox1");
//get the id of the row from the datakeys
int id = Convert.ToInt32(GridView1.DataKeys[e.RowIndex].Values[0]);
//show result for testing
Literal1.Text = "ID: " + id + "<br>Name: " + tb.Text;
//reset the edit index and rebind data
GridView1_RowCancelingEdit(null, null);
}
I've the below code working just to display the radgrid headers with a button "Add new Course". Initially on page load I have no data to bind to radgrid. On "Add new Course" button click I add a new row to the RadGrid with 2 textboxes and 2 dropdownlist(binded from db). Each row should have "remove row' button. I've these working. Now my issue is I need to restore the data that has been entered by user when the user is trying to add another new row to the grid. And also how do I remove the row? Kindly help me by your suggestions or hightlight me the mistake in my existing code. thanks in advance.
<telerik:RadGrid ID="RadGrid1" runat="server" AutoGenerateColumns="false" MasterTableView-CommandItemSettings-ShowAddNewRecordButton="false" MasterTableView-CommandItemSettings-ShowRefreshButton="false" OnNeedDataSource="RadGrid1_NeedDataSource"
OnItemDataBound="RadGrid1_ItemDataBound" OnItemCommand="RadGrid1_ItemCommand">
<MasterTableView Width="100%" HeaderStyle-Font-Bold="true" CommandItemStyle-Font-Bold="true" DataKeyNames="IsAdd,BusID" CommandItemDisplay="Top" CommandItemStyle-HorizontalAlign="Right">
<CommandItemTemplate>
<asp:Button ID="IsAdd" Font-Size="Small" Font-Bold="true" CommandName="InitInsert" Text ="Add New Bus" runat="server" />
</CommandItemTemplate>
<Columns>
<telerik:GridTemplateColumn UniqueName="BusID" HeaderText="Bus #" DataField="BusID">
<ItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</ItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridTemplateColumn UniqueName="Name" HeaderText="Bus Series" DataField="Name">
<ItemTemplate>
<asp:DropDownList ID="SeriesDropDown" DataTextField="SeriesName" runat="server" AutoPostBack="false"></asp:DropDownList>
</ItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridTemplateColumn UniqueName="Name" HeaderText="Bus Group" DataField="Name">
<ItemTemplate>
<asp:DropDownList ID="GroupDropDown" DataTextField="GroupName" runat="server" AutoPostBack="false"></asp:DropDownList>
</ItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridTemplateColumn UniqueName="Name" HeaderText="VIN" DataField="Name">
<ItemTemplate>
<asp:TextBox ID="TextBox4" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Remove Row" CommandName="Delete" />
</ItemTemplate>
</telerik:GridTemplateColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
<asp:Button ID="savebtn" runat="server" Font-Bold="true" Text="Save Rows"/>
aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
if (!IsPostBack)
{
dt.Columns.Add("BusID");
dt.Columns.Add("Name");
dt.Columns.Add("IsAdd");
dt.Rows.Add(1, "Name1", false);
dt.Rows.Add(2, "Name2", false);
dt.Rows.Add(3, "Name3", false);
Session["dt"] = dt;
}
}
protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
{
RadGrid1.DataSource = (DataTable)Session["dt"];
}
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
Button btn = new Button();
if (e.Item is GridDataItem)
{
GridDataItem item = e.Item as GridDataItem;
TextBox TextBox1 = item.FindControl("TextBox1") as TextBox;
Button Button1 = item.FindControl("Button1") as Button;
DropDownList SeriesDropDown = item.FindControl("SeriesDropDown") as DropDownList;
DropDownList GroupDropDown = item.FindControl("GroupDropDown") as DropDownList;
TextBox TextBox4 = item.FindControl("TextBox4") as TextBox;
DataSet busGroup_Dataset = admin.GetBusGroup();
GroupDropDown.DataSource = busGroup_Dataset;
GroupDropDown.DataBind();
DataSet busSeries_Dataset = admin.GetBusSeries();
SeriesDropDown.DataSource = busSeries_Dataset;
SeriesDropDown.DataBind();
bool isAdd = Convert.ToBoolean(item.GetDataKeyValue("IsAdd"));
if (isAdd)
{
TextBox1.Visible = SeriesDropDown.Visible = GroupDropDown.Visible = TextBox4.Visible = true;
btn.Visible = true;
RadGrid1.DataSource = Session["dt"];
}
else
{
TextBox1.Visible = SeriesDropDown.Visible = GroupDropDown.Visible = TextBox4.Visible = false;
Button1.Visible = false;
}
}
}
protected void RadGrid1_ItemCommand(object sender, GridCommandEventArgs e)
{
if (e.CommandName == RadGrid.InitInsertCommandName)
{
DataTable dt = (DataTable)Session["dt"];
dt.Rows.Add(0, string.Empty, true);
RadGrid1.MasterTableView.IsItemInserted = false;
e.Canceled = true;
RadGrid1.Rebind();
}
if (e.CommandName == "Delete")
{
string ID = e.Item.OwnerTableView.DataKeyValues[e.Item.ItemIndex]["0"].ToString();
DataTable table = (DataTable)Session["dt"];
if (table.Rows.Find(ID) != null)
{
table.Rows.Find(ID).Delete();
table.AcceptChanges();
Session["dt"] = table;
}
RadGrid1.Rebind();
}
}
Telerik RadGrid provides rich server API for inserting new data,
updating existing data and deleting data.
As telerik admin told you on official forum read the doc as i told you to do so 8 day earlier.
See the magic in action in the demo , learn more about it in the doc :
Please look at the telerik asp demo about DATA EDITING.
There is so mutch information about Data Editing
Let me do it for you !
The following exemple where developped in a new/clean telerik project you can just copy past them to try.
1/. With Advance binding Aka onNeedDataSource
In ASPX :
<telerik:RadGrid ID="RadGrid1"runat="server"
OnNeedDataSource="RadGrid1_NeedDataSource"
GroupingEnabled="False"
AutoGenerateColumns="False"
OnInsertCommand="RadGrid1_InsertCommand"
AllowSorting="True"
AllowPaging="True">
<MasterTableView CommandItemDisplay="Top" EditMode="Batch" >
<CommandItemSettings ShowExportToPdfButton="false" ShowExportToExcelButton="false" ShowPrintButton="false" />
<Columns>
<telerik:GridBoundColumn UniqueName="CourseID" HeaderText="CourseID" DataField="CourseID" DataType="System.Int32" >
</telerik:GridBoundColumn>
<telerik:GridBoundColumn UniqueName="CourseNumber" HeaderText="CourseNumber" DataField="CourseNumber" DataType="System.Int32">
</telerik:GridBoundColumn>
<telerik:GridBoundColumn UniqueName="Location" HeaderText="Location" DataField="Location" DataType="System.String" >
</telerik:GridBoundColumn>
<telerik:GridBoundColumn UniqueName="Name" HeaderText="Name" DataField="Name" DataType="System.String" >
</telerik:GridBoundColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
In CodeBehind :
public ObjectContainer myDatasource
{
get
{
if (Session["test_01"] == null)
Session["test_01"] = new ObjectContainer();
return Session["test_01"] as ObjectContainer ;
}
set { Session["test_01"] = value; }
}
protected void RadGrid1_InsertCommand(object sender, GridCommandEventArgs e)
{
YoData row = new YoData();
ObjectContainer tempo = new ObjectContainer();
GridBatchEditingEventArgument argument = e.CommandArgument as GridBatchEditingEventArgument;
Hashtable newValues = argument.NewValues;
row.CourseID = Int32.Parse(newValues["CourseID"].ToString());
row.CourseNumber = Int32.Parse(newValues["CourseNumber"].ToString());
row.Location = newValues["Location"].ToString();
row.Name = newValues["Name"].ToString();
myDatasource.YoDatas.Add(row);
}
protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e)
{
if ( ! IsPostBack )
{
for (int i = 0; i <= 8; i++)
{
YoData row = new YoData();
row.CourseID = i + 1;
row.CourseNumber = i + 1;
row.Name = "Name " + (i + 1);
row.Location = "Country " + (i + 1);
myDatasource.YoDatas.Add(row);
}
}
RadGrid1.DataSource = myDatasource.YoDatas;
}
In App_Code:
Im using object instead of DataTable, because it's easier.
namespace Demo
{
public class ObjectContainer
{
public ObservableCollection<YoData> YoDatas;
public ObjectContainer()
{
YoDatas = new ObservableCollection<YoData>();
}
public ObservableCollection<YoData> get_yoda(int mode = 0)
{
return this.YoDatas;
}
public void set_yoda(int CourseID, int CourseNumber, string Location, string Name)
{
YoData _temp = new YoData(CourseID, CourseNumber, Location, Name);
this.YoDatas.Add(_temp);
}
}
public class YoData
{
public int CourseID { get; set; }
public int CourseNumber { get; set; }
public DateTime CourseDate { get; set; }
public String Location { get; set; }
public String Name { get; set; }
public YoData()
{
CourseID = 0;
CourseNumber = 0;
CourseDate = DateTime.Now;
Location = "";
Name = "";
}
public YoData(int a, int b, DateTime c, string d, string e)
{
CourseID = a;
CourseNumber = b;
CourseDate = c;
Location = d;
Name = e;
}
public YoData(int a, int b, string d, string e)
{
CourseID = a;
CourseNumber = b;
CourseDate = DateTime.Now;
Location = d;
Name = e;
}
}
}
2/. in automatics, telerik do it for ya ( Later )
[edit comming soon....]
This is not the best solution, there must be some mistake in the code but it works. This is done with only the doc.
I hope this helps,
Regards,
Pierre.
I have a gridview in which every row contains a dropdownlist. I want to bind every dropdownlist dynamically. Can someone tell me how can i do it. Thanks in Advance
If you are using template column then you can bind your drop-down from mark-up using data-binding expressions. For example,
<asp:TemplateField HeaderText="XYZ">
<ItemTemplate>
<asp:DropDownList runat="server" ID="MyDD" DataSourceId="MyDataSource" />
</ItemTemplate>
</asp:TemplateField>
Above is assuming that your drop-down data in constant across rows. If it is changing then you can use data-binding expression such as
<asp:DropDownList runat="server" DataSource='<%# GetDropDownData(Container) %>' DataTextField="Text" DataValueField="Value" />
GetDropDownData will be a protected method in code-behind that will return the data (data-table, list, array) for the given row.
You can use GridView.RowDataBound event (or RowCreated event) in code-behind to fill drop-downs. For example,
protected void GridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// Find the drop-down (say in 3rd column)
var dd = e.Row.Cells[2].Controls[0] as DropDownList;
if (null != dd) {
// bind it
}
/*
// In case of template fields, use FindControl
dd = e.Row.Cells[2].FindControl("MyDD") as DropDownList;
*/
}
}
In addition to the proposed methods, you may also bind your controls within your markup, in this way:
<asp:GridView ID="MyGrid" runat="server" DataSourceID="MyDataSource1">
<Columns>
<asp:TemplateField>
<EditItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" SelectedValue='<%# Bind ("CustomerId") %>' DataSourceID="CustomersDataSource" DataTextField="CustomerName" DataValueField="CustomerId" >
</asp:DropDownList>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Here is your gridview
<asp:GridView ID="grvExcelData" runat="server" onrowdatabound="GridView2_RowDataBound">
<HeaderStyle BackColor="#df5015" Font-Bold="true" ForeColor="White" />
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:DropDownList ID="DrdDatabase" Width="100px" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and your RowDataBound event for the gridview would be
protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e)
{
string cities = "maxico,chennai,newdelhi,hongkong";
string [] arr = cities.Split(',');
// Instead of string array it could be your data retrieved from database.
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("DrdDatabase");
foreach (string colName in arr )
ddl.Items.Add(new ListItem(colName));
}
}
protected void gvSalesAppData_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddlCurrentPhase = (DropDownList)e.Row.FindControl("ddlCurrentPhase");
DropDownList ddlProductFamily = (DropDownList)e.Row.FindControl("ddlProductFamily");
DropDownList ddlProductGroup = (DropDownList)e.Row.FindControl("ddlProductGroup");
DropDownList ddlETProgramManager = (DropDownList)e.Row.FindControl("ddlETProgramManager");
DropDownList ddlPLMForTheProduct = (DropDownList)e.Row.FindControl("ddlPLMForTheProduct");
TrackingToolObj.BindCurrentPhases(ddlCurrentPhase);
TrackingToolObj.BindCurrentPhases(ddlProductFamily);
TrackingToolObj.BindProductGroups(ddlProductGroup);
TrackingToolObj.GetEmployeesBasedOnRoleTypeId(ddlETProgramManager, (int)OSAEnums.RoleTypes.ProgramManager, false);
TrackingToolObj.GetEmployeesBasedOnRoleTypeId(ddlPLMForTheProduct, (int)OSAEnums.RoleTypes.PLM, false);
}
}
Binding the GridView
Below is the code to Bind the GridView control with data.
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
this.BindData();
}
}
private void BindData()
{
string query = "SELECT top 10 * FROM Customers";
SqlCommand cmd = new SqlCommand(query);
gvCustomers.DataSource = GetData(cmd);
gvCustomers.DataBind();
}
private DataTable GetData(SqlCommand cmd)
{
string strConnString = ConfigurationManager.ConnectionStrings["conString"].ConnectionString;
using (SqlConnection con = new SqlConnection(strConnString))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
return dt;
}
}
}
}
Edit: My object is defined as below. I passed it into GridView1.
public class UserTestorViewModel
{
public string Username {get;set;}
public string Password {get;set;}
public Label SuiteName {get;set;}
}
I have GridView bound to a customized List<UserTestorViewModel>:
this.GridView1.DataSource = utViewModelList;
this.GridView1.DataBind();
and in the .aspx I have
<asp:TemplateField HeaderText="LoginName">
<ItemTemplate>
<asp:Label ID="LoginName" runat= "server" Text= '<%# ((ViewModels.UserTestorViewModel)Container.DataItem).User.userName %> '></asp:Label>
</ItemTemplate>
</asp:TemplateField>
this works because ViewModels.UserTestorViewModel.User.userName is string, but
<asp:TemplateField HeaderText="SuiteName">
<ItemTemplate>
<%# ((ViewModels.UserTestorViewModel)Container.DataItem).SuiteName %>
</ItemTemplate>
</asp:TemplateField>
because ViewModels.UserTestorViewModel.SuiteName is Label from System.Web.UI.WebControls
So how to bind a System.Web.UI.WebControls to <ItemTemplate> NOT the Text of the System.Web.UI.WebControls
You may place a Placeholder control in ItemTemplate and put your label control to it on the RowCreated event of the GridView:
protected void Page_Init(object sender, EventArgs e)
{
GridView1.RowCreated += new GridViewRowEventHandler(GridView1_RowCreated);
}
void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var dataItem = (KeyValuePair<int, Label>)e.Row.DataItem;
var nameLabelPlaceholder = e.Row.FindControl("NameLabelPlaceholder") as PlaceHolder;
if (nameLabelPlaceholder != null)
{
nameLabelPlaceholder.Controls.Add(dataItem.Value);
}
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSource = GetGridViewDataSource();
GridView1.DataBind();
}
}
private object GetGridViewDataSource()
{
return (from item in Enumerable.Range(1, 10)
select new KeyValuePair<int, Label>(item, new Label() { ID = string.Format("NameLabel_{0}", item), Text = string.Format("Item #{0}", item), ForeColor = System.Drawing.Color.Red }))
.ToDictionary(kvp1 => kvp1.Key, kvp2 => kvp2.Value);
}
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" DataKeyNames="Key">
<Columns>
<asp:BoundField HeaderText="Id" DataField="Key" />
<asp:TemplateField HeaderText="Name">
<ItemTemplate>
<asp:PlaceHolder runat="server" ID="NameLabelPlaceholder" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I have a GridView that includes BoundField and TemplateField elements. Some of the TemplateField elements are dynamically generated. For the sake of reference, here is the GridView that I am using
<asp:GridView ID="myGridView" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" ShowFooter="True" EnableModelValidation="True"
OnLoad="myGridView_Load" OnRowCommand="myGridView_RowCommand"
OnRowEditing="myGridView_RowEditing" OnRowDeleting="myGridView_RowDeleting"
OnRowCancelingEdit="myGridView_RowCancelingEdit"
OnRowUpdating="myGridView_RowUpdating">
<Columns>
<asp:BoundField DataField="Number" Visible="true" HeaderText="Test" />
<asp:TemplateField HeaderText="Number">
<EditItemTemplate>
<asp:TextBox ID="tb1" runat="server" Text='<%# Bind("Number") %>' />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lb1" runat="server" Text='<%# Bind("Number") %>' />
</ItemTemplate>
<FooterTemplate>
<asp:TextBox ID="ftb" runat="server" Text="[x]" />
</FooterTemplate>
</asp:TemplateField>
<%-- Dynamically Generated Columns Will Be Inserted Here --%>
<asp:TemplateField HeaderText="Actions">
<EditItemTemplate>
<asp:LinkButton ID="ulb" runat="server" Text="update" CommandName="Update" />
<asp:LinkButton ID="clb" runat="server" Text="cancel" CommandName="Cancel" />
</EditItemTemplate>
<FooterTemplate>
<asp:LinkButton ID="slb" runat="server" Text="insert"
OnClick="saveLinkButton_Click" />
</FooterTemplate>
<ItemTemplate>
<asp:LinkButton ID="elb" runat="server" Text="edit" CommandName="Edit" />
<asp:LinkButton ID="dlb" runat="server" Text="delete" CommandName="Delete" />
</ItemTemplate>
</asp:TemplateField
</Columns>
<EmptyDataTemplate>
<table border="0" cellpadding="0" cellspacing="0">
<tr><td>Number</td></tr>
<tr>
<td><asp:TextBox ID="ntb" runat="server" /></td>
<td><asp:LinkButton ID="slb2" runat="server" Text="save" OnClick="saveLinkButton_Click" /></td>
</tr>
</table>
</EmptyDataTemplate>
</asp:GridView>
When the GridView initially loads, everything is loaded properly. However, anytime I perform a command (edit, insert, delete), all of the data goes away. Oddly, the BoundField values still appear correctly. However, any TemplateField does not seem to get rendered. The code that I am using to work with this GridView is here:
public partial class GridView : System.Web.UI.Page
{
private List<string> dynamicColumnNames = new List<string>();
protected void Page_Load(object sender, EventArgs e)
{
LoadPageData();
}
protected void saveLinkButton_Click(object sender, EventArgs e)
{
}
protected void myGridView_Load(object sender, EventArgs e)
{
if (Page.IsPostBack == false)
{
BindGridData();
}
}
protected void myGridView_RowCommand(object sender, GridViewCommandEventArgs e)
{ }
protected void myGridView_RowEditing(object sender, GridViewEditEventArgs e)
{
myGridView.EditIndex = e.NewEditIndex;
BindGridData();
}
protected void myGridView_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
LoadPageData();
BindGridData();
}
protected void myGridView_RowCancelingEdit(object sender, EventArgs e)
{
myGridView.EditIndex = -1;
BindGridData();
}
protected void myGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
myGridView.EditIndex = -1;
LoadPageData();
BindGridData();
}
private void BindGridData()
{
// Create a temporary data source
DataTable tempData = new DataTable();
tempData.Columns.Add("ID");
tempData.Columns.Add("Number");
// Dynamically add template columns
foreach (string columnName in dynamicColumnNames)
{
tempData.Columns.Add(columnName);
TemplateField templateField = new TemplateField();
templateField.HeaderTemplate = new MyTemplateField(ListItemType.Header, columnName);
templateField.ItemTemplate = new MyTemplateField(ListItemType.Item, columnName);
templateField.EditItemTemplate = new MyTemplateField(ListItemType.EditItem, columnName);
templateField.FooterTemplate = new MyTemplateField(ListItemType.Footer, columnName);
myGridView.Columns.Insert(2, templateField);
}
// Add some phony data
Random random = new Random(DateTime.Now.Millisecond);
for (int i = 0; i < 10; i++)
{
DataRow tempRow = tempData.NewRow();
tempRow["Number"] = (i + 1);
foreach (string column in dynamicColumnNames)
tempRow[column] = random.NextDouble();
tempData.Rows.Add(tempRow);
}
// Bind the data to the grid
myGridView.DataSource = tempData;
myGridView.DataBind();
}
private void LoadPageData()
{
dynamicColumnNames.Add("USA");
dynamicColumnNames.Add("Japan");
dynamicColumnNames.Add("Mexico");
}
}
internal class MyTemplateField : ITemplate
{
// The type of the list item
private ListItemType listItemType;
// The value to use during instantiation
private string value1 = string.Empty;
public MyTemplateField(ListItemType listItemType, string value1)
{
this.listItemType = listItemType;
this.value1 = value1;
}
public void InstantiateIn(Control container)
{
if (listItemType == ListItemType.Item)
{
TextBox textBox = new TextBox();
textBox.ReadOnly = true;
textBox.DataBinding += new EventHandler(textBox_DataBinding);
container.Controls.Add(textBox);
}
else if (listItemType == ListItemType.EditItem)
{
TextBox textBox = new TextBox();
textBox.DataBinding += new EventHandler(textBox_DataBinding);
container.Controls.Add(textBox);
}
else if (listItemType == ListItemType.Header)
{
Literal literal = new Literal();
literal.Text = value1;
container.Controls.Add(literal);
}
else if (listItemType == ListItemType.Footer)
{
TextBox textBox = new TextBox();
container.Controls.Add(textBox);
}
}
private void textBox_DataBinding(object sender, EventArgs e)
{
TextBox textBox = (TextBox)(sender);
GridViewRow row = (GridViewRow)(textBox.NamingContainer);
textBox.Text = DataBinder.Eval(row.DataItem, value1).ToString();
}
}
How do I use commands in a GridView with Dynamically added columns? What is wrong with my code?
Thank you!
Dynamically added controls must be added on each post, you can't just add these controls on the first page load. Try removing your BindGridData() from within the Page.IsPostBack == false.