Store checked checkbox in gridview in database ASP.NET C# - c#

I am able to retrieve out data from database to show which is Y and N using checkbox in gridview. However now i want to to able to store which checkbox is checked back into the database after editing.
What i did so far:
.aspx
<asp:GridView ID="SiteGridView" runat="server" CssClass="datagrid"
GridLines="Vertical" AutoGenerateColumns="False"
Width="100%"
AllowPaging="True" AllowSorting="True"
DataKeyNames="promoID" OnRowCommand="GvPage_RowCommand"
OnPageIndexChanging="GvPage_PageIndexChanging"
OnSorting="GvPage_Sorting"
OnRowDatabound="SiteGridView_RowDataBound"
OnRowEditing="SiteGridView_RowEditing">
<Columns>
<asp:TemplateField HeaderText="Default">
<ItemTemplate>
<asp:CheckBox ID="process_flag" runat="server"
Checked='<%# bool.Parse(Eval("PROCESSED").ToString()) %>'
Enable='<%# !bool.Parse(Eval("PROCESSED").ToString()) %>' />
</ItemTemplate>
<ItemStyle Width="20%" />
</asp:TemplateField>
</Columns>
</asp:GridView>
CodeBehind:
SqlCommand cmd = new SqlCommand("SELECT * , CAST(CASE defaults WHEN 'Y' THEN 1 ELSE 0 END AS BIT) AS PROCESSED FROM Promotions");
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
da.SelectCommand = cmd;
// Save results of select statement into a datatable
da.Fill(dt);
SiteGridView.DataSource = dt;
SiteGridView.DataBind();
protected void SiteGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//check userrole & display accrodingly
if (Session["ROLE"].ToString() != "SA")
{
//ImageButton btnEdit = (ImageButton)e.Row.FindControl("btnDelete");
//btnEdit.Visible = false;
SiteGridView.Columns[4].Visible = false;
}
}
}

Have you tried:
Checked='<%# Eval("PROCESSED")%>'
If so, what error messages have you gotten?

For some reason Checkboxes do not trigger GridView RowCommand events. It probably can be done with appropriate calls to ClientScript.GetPostBackEventReference(), but thats a whole other level of complexity. So, in order to act on a CheckBox click and handle events individually:
(NB: I've stripped out much of your coding to clarify my points.)
In your CheckBox set AutoPostBack="true"
Add a handler for OnCheckedChanged.
Make sure the DataKey contains the pk of the row you need to update with the CheckBox State
// Simplified version of your markup
<asp:GridView ID="SiteGridView" runat="server"
DataKeyNames="promoID"
OnRowDataBound="SiteGridView_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Default">
<ItemTemplate>
<asp:CheckBox ID="process_flag" runat="server"
Checked='<%# bool.Parse(Eval("PROCESSED").ToString()) %>'
Enable='<%# !bool.Parse(Eval("PROCESSED").ToString()) %>'
OnCheckedChanged="process_flag_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
In the RowDataBound event, find the CheckBox and add the Row Index as an attribute
// Merge this with your `RowDataBound` event
protected void SiteGridView_RowDataBound( object sender, GridViewRowEventArgs e ) {
if ( e.Row.RowType == DataControlRowType.DataRow ) {
CheckBox cbx = ( CheckBox ) e.Row.FindControl( "CheckBox1" );
cbx.Attributes[ "data-row-idx" ] = e.Row.RowIndex.ToString();
}
}
Handle the CheckChanged event:
// Add this handler to your code
protected void process_flag_CheckedChanged( object sender, EventArgs e )
{
CheckBox cbx = ( CheckBox ) sender;
Int32 rowidx = Convert.ToInt32(cbx.Attributes["data-row-idx"]);
Int32 pk = (Int32) GridView4.DataKeys[rowidx].Value;
// simple way to see event arguments before actually touching the database
GridView4.Caption = string.Format(
"CheckChanged: Row {0}, State: {1}, RowPK: {2} ", rowidx , (cbx.Checked ? "Checked" : "Unchecked"), pk );
// Save Data and rebind the gridview to reflect changes
// Verify your parameters before attempting an actual update
// YourDatabaseCallWithAppropriateParamaters( ... );
GridView1.DataBind();
}

First of all use a foreach loop to findout which rows are checked. Then store ID of those rows in a List.
foreach (GridViewRow row in SiteGridView.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
CheckBox chkRow = (row.Cells[0].FindControl("process_flag") as CheckBox);
if (chkRow.Checked)
{
string ID = row.Cells[columnID].Text;

Related

Asp.Net C# Delete row from dataTable gridview on button click

I'm displaying a datatable that selects a number of elements from the database (IncomingsId, Type, Cost, Frequency) and I'm not sure how to delete a row when a button is clicked.
I've tried many solutions so far but nothing is working.
Here is the button I have within my Grid view
<asp:TemplateField HeaderText="Delete">
<ItemTemplate>
<asp:button id="DeleteRowButton" text="Delete Record" onclick="DeleteRowButton_Click" runat="server"/>
</ItemTemplate>
</asp:TemplateField>
And here is the code behind this page were I am creating the datatable.
SqlConnection con;
public _Default()
{
con = new SqlConnection(#"MySQLConnection");
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DisplayRecord();
}
}
public DataTable DisplayRecord()
{
string userId = (HttpContext.Current.User.Identity.GetUserId());
SqlDataAdapter Adp = new SqlDataAdapter("select * from Incomings where AspNetUsersId = '" + userId +"'", con);
DataTable Dt = new DataTable();
Dt.AcceptChanges();
Adp.Fill(Dt);
grid1.DataSource = Dt;
grid1.DataBind();
return Dt;
}
public void DeleteRowButton_Click(object sender, EventArgs e)
{
}
Cheers in advance for any help. I'm sure it's a simple resolution
You need a way for your code to know which ID to delete. Here is how I would normally do it:
Replace your button with an ItemTemplate, and add the button in here instead:
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:Button Text="Delete" runat="server" CommandArgument='<%# Eval("userId") %>' CommandName="Delete" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
When you have the button this way, you now have access to a CommandArgument and CommandName attributes. Notice the argument I am passing is Eval("userId"), the command name (as you will see later) is used to recognize what action you want to execute (this could be anything, is just a name).
Replace the CommandArgument with whatever value(s) you want to pass to the server, using the name that came from the database/datasource (I am guessing it would be userId).
Then, to capture this you need to implement the RowCommand event of the GridView, and intercept the correct CommandName:
public void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
string userId = e.CommandArgument.ToString();
//do something with the id
}
}
Here you have to make sure the CommandName in your button, matches to whatever action you want to execute in the RowCommand. This should do the trick.
Don't forget to bind the event to your GridView:
<asp:GridView OnRowCommand="GridView1_RowCommand" ID="GridView1" runat="server">
...
</asp:GridView>
just use this for the front-end code
<asp:GridView ID="grid1" OnRowDeleting="OnRowDeleting" DataKeyNames="deleteR" runat="server" AutoGenerateColumns="False" CellPadding="4" GridLines="None" style="width:100%" >
<columns>
<asp:TemplateField HeaderText="Delete Row">
<ItemTemplate>
<asp:Button ID="btnDelete" runat="server" class="btn btn-primary" Text="Delete" CommandName="Delete" OnRowDataBound="OnRowDataBound" />
</ItemTemplate>
</asp:TemplateField>
And have this in behind it:
protected void OnRowDeleting(object sender, GridViewDeleteEventArgs e)
{
int deleteR= Convert.ToInt32(grid1.DataKeys[e.RowIndex].Values[0]);
//have a sql statement here that add's the parameter ID for the row you want to delete, something like
SqlCommand com = new SqlCommand ("Delete FROM yourdatabase Where yourID = #yourID"
com.Parameters.AddWithValue("#yourID", yourID)
}
What you're looking for is indeed a simple solution.
You can use a foreach loop to search all DataRows within the DataTable for some kind of ID.Here's an example of what I mean:
String s = "/* IncomingsId for what you want to delete */";
foreach (DataRow r in dt.Rows) {
if (r["IncomingsId"].ToString().Equals(s)) {
dt.Rows.Remove(r);
}
}
Just a quick update for anyone that's helped me, thanks for your advice.
Asp.Net has it's own built in AutoGenerateDeleteButton and I set that to true and ran a bit of code behind it.
A simple solution that really shouldn't have taken me all day to complete!

How to bind string to grid?

I want to display data in gridview based on check box selection from another grid view. The given below code getting values into from first gridview based on check box selection. I want to bind that values into second grid. Help me to find a proper solution. Thank you.
Code :
protected void btnAssign_Click(object sender, EventArgs e)
{
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
CheckBox chkRow = (row.Cells[2].FindControl("CheckBox1") as CheckBox);
if (chkRow.Checked)
{
string[] EmpId = new string[] { row.Cells[0].Text };
string[] EmpName = new string[] { row.Cells[1].Text};
// I want to display emp id and emp name on gridview 2 based on check box selection. How can I do. Help me to find a proper solution
GridView2.DataSource = EmpId;
GridView2.DataBind();
}
}
}
}
ASPX:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="EmployeeID" HeaderText="Employee ID" ReadOnly="True" SortExpression="EmployeeID" />
<asp:BoundField DataField="FirstName" HeaderText="Employee Name" ReadOnly="True" SortExpression="FirstName" />
<asp:TemplateField HeaderText="Select" SortExpression="Select">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:CheckBox ID="CheckBox1" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:GridView ID="GridView2" runat="server"> </asp:GridView>
The given below image is showing data in grid view based on drop-down selection. After that I want to select some rows and click assign then I have to display the selected rows in new gridview.
Image :
If you don't already have a strong type defined to represent your selected Employee, you could create a Dictionary to store your selected employees. Upon completing your iteration over GridView1's rows to get the selected employees, you could use the dictionary as the datasource for GridView2 and bind to the Key and Value of each entry.
protected void btnAssign_Click(object sender, EventArgs e)
{
Dictionary<int, string> selectedEmployees = new Dictionary<int, string>();
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
CheckBox chkRow = (row.Cells[2].FindControl("CheckBox1") as CheckBox);
if (chkRow.Checked)
{
selectedEmployees.Add(int.Parse(row.Cells[0].Text), row.Cells[1].Text);
}
}
}
if (selectedEmployees.Any())
{
gridView2.DataSource = selectedEmployees;
gridView2.DataBind();
}
}
UPDATE: Updated the code to account for the exception that you were receiving with the sample code provided

ASP.NET c# Checkboxlist in a template field

I a newbie to asp.net. I have created a DB table in sqlserver with 3 columns; ImageID, Filename & Score.
FileName is C:\pics\beads.png or C:\pics\moreimages\scenary.jpeg.
Using C# asp.net, I have created a GridView. This Gridview should populate
(column 1)ImageID and get the image from the Filename (column2) and I have 2 Checkboxlist created as shown below which should accept score for the images from user and save it into the DB table.
Question 1 .
I am able to populate Image ID, but Images are not getting populated.
Question 2.
I do not know how to access the checkboxlist since it is in template. The checked is in the default select and doesn't change even if I click on it. Which method/property should be used to do save the selection to the database. Here's my code
<form id="form1" runat="server">
<p style="height: 391px">
<asp:GridView ID="GridView1" runat="server" Caption="Logos" Height="299px" Width="577px" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="ImageID" HeaderText="ImageID" />
<asp:ImageField DataImageUrlField="FileName" ControlStyle-Width="100"
ControlStyle-Height="100" HeaderText="Image" AlternateText="No image">
<ControlStyle Height="100px" Width="100px"></ControlStyle>
</asp:ImageField>
<asp:TemplateField HeaderText="Score" AccessibleHeaderText="CheckBoxList" ValidateRequestMode="Enabled">
<ItemTemplate>
<asp:CheckBoxList runat="server" AutoPostBack="true" RepeatColumns="3" ID="test">
<asp:ListItem Selected="True" Value="5">Good</asp:ListItem>
<asp:ListItem Value="0">Not Good </asp:ListItem>
<asp:ListItem Value="3">OK</asp:ListItem>
</asp:CheckBoxList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Save" Width="130px" />
<asp:Button ID="Button2" runat="server" OnClientClick="javaScript:window.close(); return false;" Text="Exit" Width="102px" />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</p>
</form>
public string sqlSel = #"SELECT TOP 3 [ImageID],FileName FROM [db1].[ImagesTest] where [Score] is null";
protected void Page_Load(object sender, EventArgs e)
{
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString))
{
connection.Open();
SqlCommand cmdSel = new SqlCommand(sqlSel, connection);
SqlDataReader reader1 = cmdSel.ExecuteReader();
while (reader1.Read())
{
DataSet ds = GetData(sqlSel);
if (ds.Tables.Count > 0)
{
GridView1.DataSource = ds;
GridView1.DataBind();
}
else
{
Response.Write("Unable to connect to the database.");
}
}
}
}
private DataSet GetData(string cmdSel)
{
String strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString;
DataSet ds = new DataSet();
try
{
SqlConnection con = new SqlConnection(strConnString);
SqlDataAdapter sda = new SqlDataAdapter(cmdSel,con);
sda.Fill(ds);
}
catch (Exception ex)
{
Response.Write("IN EXCEPTION "+ex.Message);
return null;
}
return ds;
}
Thanks for ur time
Rashmi
There are several issues with your code, here is what it should be fixed:
How to fix the images (Question 1)
As #Guilherme said in the comments, for images use URLs instead of disk paths.
Replace the images disk paths C:\pics\beads.png or C:\pics\moreimages\scenary.jpeg to something like Images/beads.png and Images/scenary.jpeg.
For this to work, you will need to have a folder named Images that contains these two files on the same directory level as your .aspx file.
Adjust your GridView1 declaration in the ASPX file
On your GridView1 declaration you should:
attach a handler to the OnRowDataBound event. This will allow you to properly bind the Score dataset column to the Score gridview column
set the DataKeyNames property on the grid to what should be the primary key for your images table (in this case DataKeyNames="ImageID")
use a RadioButtonList instead of a CheckboxList, because according to your dataset you can only set one value, which is what the RadioButtonList does. The CheckboxList is normally used when multiple selection is needed.
attach a handler to the SelectedIndexChanged event on the RadioButtonList. This will allow you to save the new values to the database (Question 2)
Here's how your GridView declaration should look like:
<asp:GridView ID="GridView1" runat="server" Caption="Logos" Height="299px" Width="577px" AutoGenerateColumns="False" OnRowDataBound="GridView1_RowDataBound" DataKeyNames="ImageID">
<Columns>
<asp:BoundField DataField="ImageID" HeaderText="ImageID" />
<asp:ImageField DataImageUrlField="FileName" ControlStyle-Width="100"
ControlStyle-Height="100" HeaderText="Image" AlternateText="No image">
<ControlStyle Height="100px" Width="100px"></ControlStyle>
</asp:ImageField>
<asp:TemplateField HeaderText="Score" AccessibleHeaderText="RadioButtonList" ValidateRequestMode="Enabled">
<ItemTemplate>
<asp:RadioButtonList runat="server" AutoPostBack="true" RepeatColumns="3" ID="test" OnSelectedIndexChanged="test_SelectedIndexChanged">
<asp:ListItem Value="5">Good</asp:ListItem>
<asp:ListItem Value="0">Not Good </asp:ListItem>
<asp:ListItem Value="3">OK</asp:ListItem>
</asp:RadioButtonList>
<!-- UPDATED! - keep the old values in a hidden field -->
<asp:HiddenField runat="server" ID="hfOldScore" Value='<%# Eval("Score") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Adjust your code behind value in your .ASPX.CS file (Question 2)
On the code behind, you will also need to:
Make sure you are binding to the GridView only once in the Page_Load event, by checking the IsPostBack property
(Optional, but recommended) Move the logic of getting data (with the SQLConnection code) in a separate method that will handle only data retrieval
Implement the handler for the OnRowDataBound event. This will bind any values from the Score column to the RadioButtonList control
Implement the handler for the SelectedIndexChecked event of the RadioButtonList control. This will allow you to save to the database the new values
Finally, here's the entire code-behind code:
protected void Page_Load(object sender, EventArgs e)
{
//bind only the first time the page loads
if (!IsPostBack)
{
DataSet ds = GetData(sqlSel);
if (ds.Tables.Count > 0)
{
GridView1.DataSource = ds;
GridView1.DataBind();
}
else
{
Response.Write("Unable to connect to the database.");
}
}
}
private DataSet GetData(string cmdSel)
{
//normally you should query the data from the DB
//I've manually constructed a DataSet for simplification purposes
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("ImageID", typeof(int)));
dt.Columns.Add(new DataColumn("FileName", typeof(string)));
dt.Columns.Add(new DataColumn("Score", typeof(int)));
dt.Rows.Add(100, #"Images/beads.png", 0);
dt.Rows.Add(200, #"Images/moreimages/scenary.jpeg", 3);
dt.Rows.Add(300, #"Images/moreimages/scenary.jpeg", 5);
ds.Tables.Add(dt);
return ds;
}
protected void Button1_Click(object sender, EventArgs e)
{
//UPDATED - iterate through all the data rows and build a dictionary of items
//to be saved
Dictionary<int, int> dataToUpdate = new Dictionary<int, int>();
foreach (GridViewRow row in GridView1.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
int imageID = (int)GridView1.DataKeys[row.RowIndex].Value;
int oldScore;
int newScore;
int.TryParse((row.FindControl("hfOldScore") as HiddenField).Value, out oldScore);
int.TryParse((row.FindControl("test") as RadioButtonList).SelectedValue, out newScore);
if (oldScore != newScore)
{
dataToUpdate.Add(imageID, newScore);
}
}
}
//update only the images that were changed
foreach (var keyValuePair in dataToUpdate)
{
SaveToDB(keyValuePair.Key, keyValuePair.Value);
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//we are only interested in the data Rows
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRow dataRow = (e.Row.DataItem as DataRowView).Row;
//manually bind the Score column to the RadioButtonlist
int? scoreId = dataRow["Score"] == DBNull.Value ? (int?)null : (int)dataRow["Score"];
if (scoreId.HasValue)
{
RadioButtonList test = e.Row.FindControl("test") as RadioButtonList;
test.ClearSelection();
test.SelectedValue = scoreId.Value.ToString();
}
}
}
protected void test_SelectedIndexChanged(object sender, EventArgs e)
{
RadioButtonList test = sender as RadioButtonList;
GridViewRow gridRow = test.NamingContainer as GridViewRow;
//obtain the current image Id
int imageId = (int)GridView1.DataKeys[gridRow.RowIndex].Value;
//obtain the current selection (we will take the first selected checkbox
int selectedValue = int.Parse(test.SelectedValue);
//UPDATED! - saves are now handled on the Save button click
//SaveToDB(imageId, selectedValue);
}
private void SaveToDB(int imageId, int score)
{
//UPDATED!
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnectionString"].ConnectionString))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.Parameters.Add("#ImageID", imageId);
command.Parameters.Add("#Score", score);
command.CommandText = #"update [db1].[ImagesTest] set Score = #Score where [ImageID] = #ImageID";
command.ExecuteNonQuery();
}
}
}
UPDATED!
The declaration of the GridView1 now contains a hidden field containing the Score value. You can use this hidden field to determine which row has changed, so you can trigger a save only on the changed ones
Save is now done on the click of the Save button, by iterating through the rows of the grid an building a Dictionary<int,string> to keep only the changes.
SaveToDB method should work, but I cannot test this myself.
Question 2:
To access your checkbox you can use.
GridViewRow row = GridView1.Rows[i];
CheckBox Ckbox = (CheckBox)row.FindControl("test");
For Question 1
Instead of ImageField you can use use ASP:Image in Templatefield like this
<asp:TemplateField HeaderText="Score" AccessibleHeaderText="CheckBoxList" ValidateRequestMode="Enabled">
<ItemTemplate>
<asp:Image ID="imageControl" runat="server" ImageUrl='<%# Eval("Filename") %>'></asp:Image>
</ItemTemplate>
</asp:TemplateField>
For Question 2
This is one of the example for how to access each Checkbox list inside gridview
For Each gvr As GridViewRow In Gridview1.Rows
If (CType(gvr.FindControl("CheckBox1"), CheckBox)).Checked = True Then
ReDim uPrimaryid(iCount)
uPrimaryid(iCount) = New Integer
uPrimaryid(iCount) = gvr.Cells("uPrimaryID").Text
iCount += 1
End If
Next

Binding RowCommand to fire when any cell in a row is clicked

My GridView basically displays a summarized version of data in the database.
What I want to do is set it up so that when you click anywhere in a row in the GridView, it should execute a set procedure that'll hide the panel that contains the GridView and display a panel that will show you the details of the item you clicked.
<asp:Panel runat="server" ID="pnlList">
<div class="rightalign">
<asp:Label runat="server" ID="lblCount"></asp:Label>
</div>
<asp:GridView runat="server" ID="gvItems" DataKeyNames="mailid"
AutoGenerateColumns="false" onrowdatabound="gvItems_RowDataBound"
Width="100%" OnSelectedIndexChanged="gvItems_SelectedIndexChanged">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox runat="server" ID="chkSelect" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:Label runat="server" ID="lblStatus" Text='<%# DataBinder.Eval(Container.DataItem, "status") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="firstname" HeaderText="From" SortExpression="firstname" />
<asp:BoundField DataField="datesent" HeaderText="Date" SortExpression="datesent" DataFormatString="{0:yyyy/MM/dd HH:mm}" />
<asp:BoundField DataField="subject" HeaderText="Subject" SortExpression="subject" />
</Columns>
</asp:GridView>
</asp:Panel>
<asp:Panel runat="server" ID="pnlMail">
<p>From: <asp:Label runat="server" ID="lblFrom"></asp:Label><br />
Sent On: <asp:Label runat="server" ID="lblDate"></asp:Label><br />
Subject: <asp:Label runat="server" ID="lblSubject"></asp:Label></p>
<p><asp:Label runat="server" ID="lblMessage"></asp:Label></p>
</asp:Panel>
I figured I'd use the SelectedIndexChanged event, but I'm not sure how to actually make it fire off clicks on the cells.
Here's the code I've got:
protected void gvItems_SelectedIndexChanged(object sender, EventArgs e)
{
int index = gvItems.SelectedIndex;
string mailid = gvItems.DataKeys[index].Value.ToString();
getMailDetail(mailid);
pnlMail.Visible = true;
}
protected void getMailDetail(string id)
{
int mailid = int.Parse(id);
MySqlContext db = new MySqlContext();
string sql = "select m.datesent, m.subject, m.message, u.firstname, u.lastname from mail m inner join users u on m.senderid = u.userid where m.mailid = #id";
List<MySqlParameter> args = new List<MySqlParameter>();
args.Add(new MySqlParameter() { ParameterName = "#id", MySqlDbType = MySqlDbType.Int32, Value = mailid });
MySqlDataReader dr = db.getReader(sql, args);
if (dr.HasRows)
{
dr.Read();
lblFrom.Text = (string)dr["firstname"] + " " + (string)dr["lastname"];
lblDate.Text = (string)dr["datesent"];
lblSubject.Text = (string)dr["subject"];
lblMessage.Text = (string)dr["message"];
}
dr.Close();
}
How can I make clicks on the cells in a row fire an event that'll do the work I need done?
Any help will be appreciated!
I can see two possible solutions here. First - handle click on the row on client side, send Ajax request to some HttpHandler that will return you necessary mail details, and display the returned info. Steps to achieve this:
Assign a client side handler too row click:
protected void gvItems_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onClick"] = "showMailDetails(" + DataBinder.Eval(e.Row.DataItem, "id") + ")";
}
}
And define the client side function:
function showMailDetails(mailId) {
$.get(
url: 'url to HttpHandler here',
data: {id: mailId},
success: function(data) {
var pnlMail = $('#<%= pnlMail.ClientID %>');
// display data here
pnlMail.show()
});
}
Another way is to handle click on client side and then emulate RowCommand event by doing something like this:
protected void gvItems_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onClick"] = ""javascript:__doPostBack('" + gvItems.ClientID + "','MailDetailsCommand$" + DataBinder.Eval(e.Row.DataItem, "id") + "')";
}
}
And then on server side go like you already did, just in RowComamnd handler:
protected void gvItems_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "MailDetailsCommand") {
// ...
}
}
Although I would not recommend this method - using _doPostBack manully is not considered as a best practice.
you give a template field which consist the button or a button field and then you can the give the commandname as something and then you can use the gridview commandeventargs and based on the commandname you can do whatever you want, and you can use the OnRowCommand to fire an event :D hope this will help you .....
You can even go for adding the onclick attribute to the cell in the RowDataBound Event, if there are any restrictions of not having the button field or like that

Dynamically added controls missing during GridView RowUpdating

I have a GridView with a TemplateField column that I put PlaceHolder controls in. During the DataBound event for the GridView I dynamically add a few CheckBoxes to the PlaceHolder. That works fine and displays as expected.
My problem is that during the RowUpdating event the PlaceHolder contains no controls; my CheckBoxes are missing. I also noticed that they're missing during the RowEditing event.
I want to be able to get the values of the CheckBoxes during the RowUpdating event so I can save them to the database.
Here's some example code. I've trimmed out a lot to reduce size, but if you want to see specifics just ask and I'll be happy to add more.
HTML:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False"
ondatabound="gridView_DataBound" onrowupdating="gridView_RowUpdating"
onrowediting="gridView_RowEditing" DataKeyNames="ID">
<Columns>
<asp:TemplateField HeaderText="Countries">
<ItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</ItemTemplate>
<EditItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="editButton" runat="server" CommandName="Edit" Text="Edit"></asp:LinkButton>
</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="updateButton" runat="server" CommandName="Update" Text="Update"></asp:LinkButton>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code behind:
// This method works fine, no obvious problems here.
protected void gridView_DataBound(object sender, EventArgs e)
{
// Loop through the Holidays that are bound to the GridView
var holidays = (IEnumerable<Holiday>)gridView.DataSource;
for (int i = 0; i < holidays.Count(); i++)
{
// Get the row the Holiday is bound to
GridViewRow row = gridView.Rows[i];
// Get the PlaceHolder control
var placeHolder = (PlaceHolder)row.FindControl("countriesPlaceHolder");
// Create a CheckBox for each country and add it to the PlaceHolder
foreach (Country country in this.Countries)
{
bool isChecked = holidays.ElementAt(i).Countries.Any(item => item.ID == country.ID);
var countryCheckBox = new CheckBox
{
Checked = isChecked,
ID = country.Abbreviation + "CheckBox",
Text = country.Abbreviation
};
placeHolder.Controls.Add(countryCheckBox);
}
}
}
protected void gridView_RowEditing(object sender, GridViewEditEventArgs e)
{
// EXAMPLE: I'm expecting checkBoxControls to contain my CheckBoxes, but it's empty.
var checkBoxControls = gridView.Rows[e.NewEditIndex].FindControl("countriesPlaceHolder").Controls;
gridView.EditIndex = e.NewEditIndex;
BindData();
}
protected void gridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
// EXAMPLE: I'm expecting checkBoxControls to contain my CheckBoxes, but it's empty.
var checkBoxControls = ((PlaceHolder)gridView.Rows[e.RowIndex].FindControl("countriesPlaceHolder")).Controls;
// This is where I'd grab the values from the controls, create an entity, and save the entity to the database.
gridView.EditIndex = -1;
BindData();
}
This is the article that I followed for my data binding approach: http://www.aarongoldenthal.com/post/2009/04/19/Manually-Databinding-a-GridView.aspx
You need to call your BindData() method on page load.
"Dynamic controls or columns need to be recreated on every page load, because of the way that controls work. Dynamic controls do not get retained so you have to reload them on every page postback; however, viewstate will be retained for these controls."
See Cells in gridview lose controls on RowUpdating event
Also in the article you linked, there is an ItemTemplate and an EditItemTemplace because they have different displays, i.e. read only and editable. Yours are the same so I think you could simplify your design:
<asp:GridView ID="gridView" runat="server" AutoGenerateColumns="False" DataKeyNames="ID" ondatabound="gridView_DataBound">
<Columns>
<asp:TemplateField HeaderText="Countries">
<ItemTemplate>
<asp:PlaceHolder ID="countriesPlaceHolder" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="editButton" runat="server" Text="Edit" onclick="editButton_Click" ></asp:LinkButton>
<asp:LinkButton ID="updateButton" runat="server" Text="Update" onclick="updateButton_Click" ></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Code Behind:
protected void gridView_DataBound(object sender, EventArgs e)
{
// Loop through the Holidays that are bound to the GridView
var holidays = (IEnumerable<Holiday>)gridView.DataSource;
for (int i = 0; i < holidays.Count(); i++)
{
// Get the row the Holiday is bound to
GridViewRow row = gridView.Rows[i];
// Get the PlaceHolder control
var placeHolder = (PlaceHolder) row.FindControl("countriesPlaceHolder");
var countryCheckBox = new CheckBox
{
Checked = true,
ID = "auCheckBox",
Text = "Aus",
Enabled = false
};
placeHolder.Controls.Add(countryCheckBox);
var editButton = (LinkButton)row.FindControl("editButton");
editButton.CommandArgument = i.ToString();
var updateButton = (LinkButton)row.FindControl("updateButton");
updateButton.CommandArgument = i.ToString();
updateButton.Visible = false;
}
}
protected void editButton_Click(object sender, EventArgs e)
{
LinkButton editButton = (LinkButton) sender;
int index = Convert.ToInt32(editButton.CommandArgument);
GridViewRow row = gridView.Rows[index];
// Get the PlaceHolder control
LinkButton updateButton = (LinkButton)row.FindControl("updateButton");
updateButton.Visible = true;
editButton.Visible = false;
CheckBox checkbox = (CheckBox)row.FindControl("auCheckBox");
if (checkbox != null)
{
checkbox.Enabled = true;
// Get value and update
}
}
protected void updateButton_Click(object sender, EventArgs e)
{
LinkButton updateButton = (LinkButton)sender;
int index = Convert.ToInt32(updateButton.CommandArgument);
GridViewRow row = gridView.Rows[index];
// Get the PlaceHolder control
LinkButton editButton = (LinkButton)row.FindControl("updateButton");
editButton.Visible = true;
updateButton.Visible = false;
CheckBox checkbox = (CheckBox)row.FindControl("auCheckBox");
if (checkbox != null)
{
// Get value and update
checkbox.Enabled = false;
}
}
If you want to be it enabled from the get go, just remove the enabled checks and you can delete your edit button.
Hope that helps.

Categories