Make DataTable values as DropDown selected values in GridView - c#

I have a datatable with values and I need to assign them as default values to gridview dropdown list on button click event. I have tried writing the below code and it retains only the last row values. How can I retain all the rows?
Am I missing to add rows to the GridView?
For example: DataTable now has three rows and in GridView only the third row has the default values from DataTable and the first rows are empty.
DataTable dtValues = dtSource;
if (dtValues.Rows.Count > 0)
{
for (int i = 1; i <= dtValues.Rows.Count; i++)
{
RadComboBox ID = (RadComboBox)gvGrid.Rows[i].Cells[1].FindControl("radID");
RadComboBox Names = (RadComboBox)gvGrid.Rows[i].Cells[2].FindControl("radName");
ID.SelectedValue = dtValues.Rows[i]["ID"].ToString();
Names.SelectedValue = dtValues.Rows[i]["Name"].ToString();
}
}
Can anyone please correct me if I'm doing something wrong?

You should need to use RowDataBound event of GridView as like below and populate it from DataTable as DataSource:
protected void gvGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
// check if row is not in edit mode
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataTable dtValues = dtSource;
// get dropdownlist from gridview
var ddl = e.Row.FindControl("YourDropDown") as DropDownList;
if (ddl != null)
{
ddl.DataSource = dtValues;
ddl.DataTextField = "Name"; // add text to dropdownlist
ddl.DataValueField = "ID"; // add value to dropdownlist
ddl.DataBind();
// add default selected value
ddl.Items.Insert(0, new ListItem("----- Select a Value -----", "0"));
}
}
}
Note: Don't forget to add OnRowDataBound event gvGrid_RowDataBound to your GridView.

Related

ASP.NET Add Hyperlink for whole row of Datatable/Gridview

I'm generating a DataTable with some data and using it as DataSource for a GridView that will be added to an ASP.NET-Webpage.
GridView gvItems = new GridView();
DataTable dtItems = new DataTable();
dtItems.Columns.Add("name");
dtItems.Columns.Add("description");
dtItems.Columns.Add("count");
foreach(var item in items)
{
string name = item.name;
string description = item.description;
string count = item.count.ToString();
string link = "~/Views/Items.aspx?item=" + item.name;
string linkName = item.name;
dtItems.Rows.Add(name, description, count)
}
gvItems.DataSource = dtItems;
gvItems.DataBind();
PlaceHolder.Controls.Add(gvItems)
Is it possible to generate a Hyperlink for each whole row that is added?
I want a detailed page of an item to be opened if someone clicks somewhere inside of a row.
You cannot add a link to an entire row directly, but you can do it with an attribute and some jQuery. For that you need the RowDataBound event. But since you are creating a GridView dynamically you need to add it with code.
gvItems.RowDataBound += GvItems_RowDataBound;
gvItems.DataSource = dtItems;
gvItems.DataBind();
Then the RowDataBound method itself.
private void GvItems_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is a datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//cast the row back to a datarowview
DataRowView row = e.Row.DataItem as DataRowView;
//add the url as an attribute to the row
e.Row.Attributes.Add("data-url", row["link"].ToString());
//give the row a class to the jquery click event can be bound to it
e.Row.Attributes.Add("class", "ClickableRow");
}
}
Then for some front end code to handle the click.
<script type="text/javascript">
$(document).ready(function () {
$(".ClickableRow").click(function () {
location.href = $(this).data("url");
});
});
</script>

ComboBox DropDown where user cannot enter text

I have a Windows Form with a DataGridView and a ComboBox. When a user clicks a row in the DGV, I want the ComboBox text to display the value in the row whether the value exists in the ComboBox or not. However, I also want users to be able to select items in the ComboBox without the ability to enter custom text.
Changing the DropDownStyle to DropDownList will not work because then I will not be able to programatically enter values that don't exist.
One idea I had was to change the style to DropDownList and temporarily add custom items and then remove them when they are no longer selected in the DGV, but I was hoping for a more elegant solution. Any help would be appreciated.
You can use the DataError event to your advantage here and add the missing item to the collection by casting the cell to a DataGridViewComboBoxCell and add the missing item to its collection:
public Form1() {
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("C1");
DataRow dr1 = dt.NewRow();
dr1[0] = "ccc";
dt.Rows.Add(dr1);
DataRow dr2 = dt.NewRow();
dr2[0] = "xxx";
dt.Rows.Add(dr2);
dgv.AutoGenerateColumns = false;
var dgvCB = new DataGridViewComboBoxColumn();
dgvCB.Items.AddRange(new string[] { "aaa", "bbb", "ccc", "ddd" });
dgv.Columns.Add(dgvCB);
dgv.Columns[0].DataPropertyName = "C1";
dgv.DataError += dgv_DataError;
dgv.DataSource = dt;
}
void dgv_DataError(object sender, DataGridViewDataErrorEventArgs e) {
if (e.ColumnIndex == 0) {
string value = dt.Rows[e.RowIndex][e.ColumnIndex].ToString();
var dgvCB = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex];
if (!dgvCB.Items.Contains(value)) {
dgvCB.Items.Add(value);
}
}
}
What about creating the combobox_KeyPress and then add the line e.KeyChar = Nothing that will prevent any keystrokes into the box

Postback resets the selectedValue of DropdownList inside GridView

My gridview has 2 columns - DropDownList & TextBox. The DDL is databound by a datatable. The SelectedIndex Change of DDL will populate its Textbox and also add a new row. All of this works fine, but the selected values of DDLs of previous rows, reset to 0 index, when a new row is added.The textbox values remain intact though. How can I retain the DDL selected values when adding new rows.
For eg. if I select 'abc' from dropdown of row 1, it populates its text field and also adds a new row. But with the postback happening, abc does not remain selected in row 1 ddl:
LOGIN PHONE
1 123456789
2
ASPX:
<asp:GridView ID="gvCommissions" runat="server"
OnRowDataBound="gvCommissions_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="LOGIN" ItemStyle-Width="29%">
<ItemTemplate>
<asp:DropDownList ID="ddlLogin" runat="server" Width="98%"
DataTextField="login" DataValueField="id"
OnSelectedIndexChanged="ddlLogin_SelectedIndexChanged" AutoPostBack="true" >
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="PHONE" ItemStyle-Width="12%">
<ItemTemplate>
<asp:TextBox ID="txtPhone" runat="server" Width="98%"
Text='<%# Eval("phone")%>' Enabled="false"></asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
CODE BEHIND:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Get values from DB, store to a datatable and then to a viewstate
GetAgentDetails();
//Adds an empty row to grid
SetInitialRow();
}
}
private void AddNewRow()
{
//Create a datatable
dtCurrentData = new DataTable();
dtCurrentData.Columns.Add("phone");
//Store values of each row to a new datarow. Add all rows to datatable
foreach (GridViewRow gvRow in gvCommissions.Rows)
{
DataRow drcurrentrow = dtCurrentData.NewRow();
drcurrentrow["phone"] = ((TextBox)gvRow.FindControl("txtphone")).Text;
dtCurrentData.Rows.Add(drcurrentrow);
}
//create an empty datarow and also add it to the new datatable.
DataRow dr = dtCurrentData.NewRow();
dr["phone"] = "";
dtCurrentData.Rows.Add(dr);
//Bind the new datatable to the grid
gvCommissions.DataSource = dtCurrentData;
gvCommissions.DataBind();
}
protected void gvCommissions_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlLogin");
dtAgents = (DataTable)ViewState["AgentsTable"];
ddl.DataSource = dtAgents;
ddl.DataBind();
ddl.Items.Insert(0, "");
}
}
When you databind in AddNewRow, the original rows are lost. You must store the dropdown selected index, together with your textbox phone value in dtCurrentData. You can then set the index of the dropdowns in your RowDataBound event, using the values your saved in dtCurrentData.
private void AddNewRow()
{
//Create a datatable
dtCurrentData = new DataTable();
dtCurrentData.Columns.Add("phone");
//new column for dropdown index
dtCurrentData.Columns.Add("ddlIndex");
//Store values of each row to a new datarow. Add all rows to datatable
foreach (GridViewRow gvRow in gvCommissions.Rows)
{
DataRow drcurrentrow = dtCurrentData.NewRow();
drcurrentrow["phone"] = ((TextBox)gvRow.FindControl("txtphone")).Text;
//get dropdown index
drcurrentrow["ddlIndex"] = ((DropDownList)gvRow.FindControl("ddlLogin")).SelectedIndex;
dtCurrentData.Rows.Add(drcurrentrow);
}
//create an empty datarow and also add it to the new datatable.
DataRow dr = dtCurrentData.NewRow();
dr["phone"] = "";
//initial drop down index
dr["ddlIndex"] = 0;
dtCurrentData.Rows.Add(dr);
//save to the viewstate like your AgentsTable
ViewState["CurrentData"] = dtCurrentData;
//Bind the new datatable to the grid
gvCommissions.DataSource = dtCurrentData;
gvCommissions.DataBind();
}
protected void gvCommissions_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DropDownList ddl = (DropDownList)e.Row.FindControl("ddlLogin");
dtAgents = (DataTable)ViewState["AgentsTable"];
ddl.DataSource = dtAgents;
ddl.DataBind();
ddl.Items.Insert(0, "");
//get the dropdown index from CurrentData
//use the current gridview's row index, since it matches the datatable
if (ViewState["CurrentData"] != null)
{
DataTable dtCurrentData = (DataTable)ViewState["CurrentData"];
ddl.SelectedIndex = Convert.ToInt32(dtCurrentData.Rows[e.Row.RowIndex]["ddlIndex"]);
}
}
}
RowDataBound gets fired every time (irrespective of whether the page is PostBack page or NOT).
You need to add that if(!IsPostBack) condition around the code where you are performing the databinding for the dropdowns in your RowDataBound event.

Visual Web Developer Putting Drowdown Menus in Table Cells

I have created a web page that displays a table. Most of the cells of the table are already filled in but some of them require user input. I would like to put drop down menus in some of these table cells such that the cell will be populated with the selection from the menu and the drop down list will disappear.
I have gotten this to work in a single cell. However, when I tried to get it to work in a second cell everything broke. I have hacked around so much trying to find the problem that I am not even sure I remember how I got the first one working now. :-)
Here is the relevant code:
protected void Page_Load(object sender, EventArgs e)
{
// Create a DropDownList control.
DropDownList DropList = new DropDownList();
// Set the properties for the DropDownList control.
DropList.ID = "TrendList";
DropList.AutoPostBack = true;
// Manually register the event-handling method for the
// SelectedIndexChanged event.
DropList.SelectedIndexChanged += new EventHandler(this.Selection_Change);
// Because the DropDownList control is created dynamically each
// time the page is loaded, the data must be bound to the
// control each time the page is refreshed.
// Specify the data source and field names for the Text and
// Value properties of the items (ListItem objects) in the
// DropDownList control.
DropList.DataSource = CreateDataSource();
DropList.DataTextField = "ColorTextField";
DropList.DataValueField = "ColorValueField";
// Bind the data to the control.
DropList.DataBind();
// Set the default selected item when the page is first loaded.
if (!IsPostBack)
{
DropList.SelectedIndex = 0;
}
// Add the DropDownList control to the Controls collection of
// the PlaceHolder control.
p1.Controls.Add(DropList);
p2.Controls.Add(DropList);
}
ICollection CreateDataSource()
{
// Create a table to store data for the DropDownList control.
DataTable dt = new DataTable();
// Define the columns of the table.
dt.Columns.Add(new DataColumn("ColorTextField", typeof(String)));
dt.Columns.Add(new DataColumn("ColorValueField", typeof(String)));
// Populate the table with sample values.
dt.Rows.Add(CreateRow("GreenUp", "GreenUp", dt));
dt.Rows.Add(CreateRow("GreenFlat", "GreenFlat", dt));
dt.Rows.Add(CreateRow("GreenDown", "GreenDown", dt));
dt.Rows.Add(CreateRow("YellowUp", "YellowUp", dt));
dt.Rows.Add(CreateRow("YellowFlat", "YellowFlat", dt));
dt.Rows.Add(CreateRow("YellowDown", "YellowDown", dt));
dt.Rows.Add(CreateRow("RedUp", "RedUp", dt));
dt.Rows.Add(CreateRow("RedFlat", "RedFlat", dt));
dt.Rows.Add(CreateRow("RedDown", "RedDown", dt));
dt.Rows.Add(CreateRow("ClearUp", "ClearUp", dt));
dt.Rows.Add(CreateRow("ClearFlat", "ClearFlat", dt));
dt.Rows.Add(CreateRow("ClearDown", "ClearDown", dt));
// Create a DataView from the DataTable to act as the data source
// for the DropDownList control.
DataView dv = new DataView(dt);
return dv;
}
DataRow CreateRow(String Text, String Value, DataTable dt)
{
// Create a DataRow using the DataTable defined in the
// CreateDataSource method.
DataRow dr = dt.NewRow();
// This DataRow contains the ColorTextField and ColorValueField
// fields, as defined in the CreateDataSource method. Set the
// fields with the appropriate value. Remember that column 0
// is defined as ColorTextField, and column 1 is defined as
// ColorValueField.
dr[0] = Text;
dr[1] = Value;
return dr;
}
void Selection_Change(Object sender, EventArgs e)
{
// Retrieve the DropDownList control from the Controls
// collection of the PlaceHolder control.
DropDownList DropList1 = (DropDownList)p1.FindControl("TrendList");
DropDownList DropList2 = (DropDownList)p2.FindControl("TrendList");
switch (sender.ToString())
{
case "p1":
s1.InnerHtml = DropList1.SelectedItem.Value;
break;
case "p2":
s2.InnerHtml = DropList2.SelectedItem.Value;
break;
}
}
And here is the relevant snippet from the table:
<td><span id="s1" runat="server"><asp:PlaceHolder ID="p1" runat="server"></asp:PlaceHolder></span>
<td><span id="s2" runat="server"><asp:PlaceHolder ID="p2" runat="server"></asp:PlaceHolder></span>
Now I realize that the switch control is all wrong since sender does not represent the id of the caller. But I need some way to distinguish which drop down menu is the caller so I know which HTML to replace. Also, I can only get one drop down menu to display at a time.
Any advice is appreciated.
Regards.
This code solved the problem:
public void EditTable()
{
ICollection trends = CreateDataSource();
for (int x = 1; x <= 27; x++)
{
DropDownList ddl = new DropDownList();
string index = x.ToString();
ddl.ID = "TrendList" + index;
ddl.AutoPostBack = true;
ddl.SelectedIndexChanged += new EventHandler(this.Selection_Change);
ddl.DataSource = trends;
ddl.DataTextField = "TrendTextField";
ddl.DataValueField = "TrendValueField";
ddl.DataBind();
if (!IsPostBack)
{
ddl.SelectedIndex = 0;
}
HtmlGenericControl span = (HtmlGenericControl)form1.FindControl("s" + index);
PlaceHolder placeHolder = (PlaceHolder)span.FindControl("p" + index);
if (placeHolder != null)
{
placeHolder.Controls.Add(ddl);
}
}
}

Retrieving all GridViewRow objects from a GridView control with paging enabled

I currently have a GridView control on my aspx page with paging enabled and I need to loop through the entire row collection/count to process the selected records. With my current code, it will only loop through the current page of GridView row.
What is the best way to accomplish this task?
Here is my current code:
ASPX page:
<asp:GridView ID="MyGridView" runat="server" AllowPaging="true" PageSize="20">
<Columns>
<!-- My Column list -->
</Columns>
</asp:GridView>
<asp:Button id="MyButton" runat="server" Text="Add" OnClick="MyButton_Click" />
code behind:
protected void MyButton_Click(object sender, EventArgs e)
{
for (int Count = 0; Count < MyGridView.Rows.Count; Count++)
{
//The row count is 20 and only contains the GridViewRow object in the current page view
//I want to retrieve the all GridViews rows so I can add them to a ReorderList control
}
}
Yes because your gridview UI is only aware of the current page.
Get the datasource and determine the row count from there...
int count = ((DataTable)MyGridView.DataSource).Rows.Count;
//or
int count = ((ICollection<SomeRecord>)MyGridView.DataSource).Count;
Simply use the following code:
//Change gridview to
GridView1.AllowPaging = false;
GridView1.DataBind();
//Transfer rows from GridView to table
for (int i = 0; i < GridView1.Rows.Count; i++)
{
if (GridView1.Rows[i].RowType == DataControlRowType.DataRow)
{
for (int j = 0; j < GridView1.Rows[0].Cells.Count; j++)
{
//Add your code here..
}
}
}
//After filling your datatable change gridview paging style back to first, ie.
GridView1.AllowPaging = true;
GridView1.DataBind();
This may help you, let me know if this was helpful for you...
I think you should get the row count from your data source's row count.
If you need to filter rows, you can use DataTable's / DataView's Select method.
EDIT : You can not get actual row count by gridview.Rows.Count if gridview is paged. Depending on your comment, I assume that you're using listDataSource generic list to bind your gridview, you can get your row count as :
List<DataSourceItem> selectedRows =
listDataSource.FindAll(delegate(DataSourceItem item)
{
// Assuming you have a IsSelected bool property
// that refers your row is selected :
return item.IsSelected;
});
int rowCount = selectedRows.Count;
use session or state to store:
protected void Set_CheckboxStatus()
{
CheckBox selectall = (CheckBox)EmployeeGrid.HeaderRow.FindControl("gcb_selectall");
ArrayList cbstatuslist = new ArrayList();
if (Session["childcbstatus"] != null)
{
cbstatuslist = (ArrayList)Session["childcbstatus"];
}
foreach (GridViewRow row in EmployeeGrid.Rows)
{
int cb_index = (int)row.DataItemIndex; //For Getting DataItemIndex of EmployeeGrid
//int cb_index = (int)row.RowIndex;
CheckBox cb_selemp = (CheckBox)row.FindControl("gcb_selemp");
CheckBox cb_active = (CheckBox)row.FindControl("gcb_active");
if (cb_selemp.Checked == true)
{
if (!cbstatuslist.Contains(cb_index))
cbstatuslist.Add(cb_index);
}
else
{
cbstatuslist.Remove(cb_index);
}
}
Session["childcbstatus"] = cbstatuslist;
}
from the arraylist you can get all row index to loop and get the value from the gridview with paging.
#CRice's answer should have been the official answer.
Here is my solution. You need to presave the gridview's data, via its DataSource, into ViewState or Session.
GridView.Rows only refers to the "visible" rows, or the page currently shown on the screen.
protected void GridView_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView gv = (GridView)sender;
DataSourceSelectArguments dss = new DataSourceSelectArguments();
//get the datasource related to the gridview
string wsDataSourceID = (gv.DataSourceID == string.Empty) ? ViewState["DataSourceID"].ToString() : gv.DataSourceID;
SqlDataSource sds = (SqlDataSource)pnlMAIN.FindControl(wsDataSourceID);
if (sds != null)
{
//load the data again but this time into a dataview object
DataView dv = (DataView)sds.Select(DataSourceSelectArguments.Empty);
if (dv != null)
{
//convert the dataview to a datatable so we can see the row(s)
DataTable dt = (DataTable)dv.ToTable();
if (dt != null)
{
//Save your data before changing pages
ViewState["AllTheData"] = dt;
gv.DataSource = dt;
gv.DataSourceID = null;
}
}
}
//now change pages!
gv.PageIndex = e.NewPageIndex;
gv.DataBind();
}
Next, when changing pages, here we save the data
protected void GridView_PageIndexChanged(object sender, EventArgs e)
{
GridView gv = (GridView)sender;
DataSourceSelectArguments dss = new DataSourceSelectArguments();
//reload the datatable back to the gridview
gv.DataSource = ViewState["AllTheData"];
gv.DataSourceID = null;
gv.DataBind();
I hope the code speaks for itself.
Thanks

Categories