Dynamic control Viewstate - c#

I am now stuck. After spending ages trying to maintain dynamically added linkbutton or label to a gridview it seems I am overwriting a checkbox state on post back.
As stated I am dynamically adding either a linkbutton or a label to a place holder in a gridview with the following:
protected void LedgerGrid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int index = e.Row.RowIndex;
if (items[index].noteID > 0)
{
PlaceHolder label = (PlaceHolder)e.Row.FindControl("HasPrevious");
LinkButton link = new LinkButton();
link.CommandName = "LinkCommand";
link.Command += new CommandEventHandler(link_Command);
link.Text = "Yes";
link.ID = index.ToString();
label.Controls.Add(link);
}
else
{
PlaceHolder label = (PlaceHolder)e.Row.FindControl("HasPrevious");
Label noNote = new Label();
noNote.Text = "No";
label.Controls.Add(noNote);
}
Here is the gridview:
<asp:GridView runat="server" ID="LedgerGrid" AutoGenerateColumns="false"
onselectedindexchanged="LedgerGrid_SelectedIndexChanged"
onrowdatabound="LedgerGrid_RowDataBound" onrowcommand="LedgerGrid_RowCommand"
>
<Columns>
<asp:TemplateField HeaderText="Notes">
<ItemTemplate>
<asp:PlaceHolder ID="HasPrevious" runat="server"></asp:PlaceHolder>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Invoice Date" DataField="invoicedate" DataFormatString="{0:d}" />
<asp:BoundField HeaderText="Invoice" DataField="invoice" />
<asp:BoundField HeaderText="Fee Debt" DataField="Fee_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Cost Debt" DataField="Cost_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="VAT Debt" DataField="VAT_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Total Debt" DataField="Total_Debt" DataFormatString="{0:C}" />
<asp:BoundField HeaderText="Client Code" DataField="ClientCode" />
<asp:ButtonField HeaderText="Matter Number" DataTextField="matternumber" CommandName="ViewMatter" />
<asp:BoundField HeaderText="Decription" DataField="matterdescription" />
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="AddInvoiceCheck" runat="server" Enabled="true" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
To make sure that my link button command works I am rebuilding the gridview as I would in the Page_load. Here is the page load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string clientCode = Server.HtmlEncode(Request.QueryString["clientcode"]);
items = DataAccess.DataAccess.GetLedgerDetails(clientCode);
ViewState["LedgerItems"] = items;
ViewState["clientcode"] = clientCode;
LedgerGrid.DataSource = items;
LedgerGrid.DataBind();
LedgerClientObject clientDetails = DataAccess.DataAccess.GetClientDetails(clientCode);
ClientCodeLabel.Text = string.Format("Group Code: {0}", clientDetails.GroupCode);
ClientNameLabel.Text = string.Format("Client Name: {0}", clientDetails.ClientName);
ClientCodeFilter.DataSource = clientDetails.ClientCodes;
ClientCodeFilter.DataBind();
}
}
To maintain the dynamically added controls on post back I am calling the following:
protected void Page_PreLoad(object sender, EventArgs e)
{
if (IsPostBack)
{
items = (List<LedgerItem>)ViewState["LedgerItems"];
LedgerGrid.DataSource = items;
LedgerGrid.DataBind();
}
}
Of course it now seems that by using this method I am overwriting the state of the check-box gridview column. Am I approaching this all wrong? I would like to be able to use the viewstate to maintain the set up of my dynamically added controls to the gridview. Is there a way I can access the state of the checkbox control form gridview before/after I reload the gridview in PreLoad event?
I am checking the state of my checkbox column with a button click as follows:
protected void Unnamed1_Click(object sender, EventArgs e)
{
NoteModel note = new NoteModel();
for (int i = 0; i < LedgerGrid.Rows.Count; i++)
{
int invoice = Convert.ToInt32(LedgerGrid.Rows[i].Cells[2].Text);
CheckBox check = (CheckBox)LedgerGrid.Rows[i].FindControl("AddInvoiceCheck");
if (check.Checked)
{
note.invoices.Add(invoice);
}
}
if (note.invoices == null)
{
string clientcode = (string)ViewState["clientcode"];
ViewState["InvoiceError"] = 1;
Response.Redirect(string.Format("Ledger.aspx?clientcode={0}", clientcode));
}
else
{
string clientcode = (string)ViewState["clientcode"];
Session["NoteObject"] = note;
Response.Redirect(string.Format("AddNote.aspx?cc={0}", clientcode));
}
}
Whenever I iterate over the checkbox controls in the gridview they are all unchecked e.g overwritten by my PreLoad code!!!

In the end I decided not to use dynamically created controls. Instead I added a buttonfield to the grid view. In my rowdatabound event I then set the visibility of the button to false if it does meet my criteria. This way view state is maintained as i do not need to create control on post back.
Seems with webforms that avoiding dynamic controls where possible is the best bet. I would still like to know which event to tap into to override viewstate re-instating controls?

Related

c#.net gridview with both (sometimes displayed) button click and row click events

I have a grid with the following definition. I have included two buttons here (different types), but I really only want one, but it must be able to be hidden under certain circumstances.
With the 'ButtonField' I was able to hide it in the RowDataBound event, however, on postback (row click event), all buttons where displayed.
Clicking this button triggers two RowCommand events, one being 'Select' and one being the 'AcceptStats', which would be okay if I could hide the button when not wanted.
The 'asp:Button' displays correctly all the time, but the click event seems to have gotten lost under the row click event.
In the RowCommand event, the CommandName is always 'Select', which comes from the row click event.
I have tried adding OnClick="btnAcceptStats_Click" to the asp:Button, but it doesn't trigger either.
<asp:GridView ID="gvApsimFiles" runat="server" AutoGenerateColumns="false" CssClass="GridViewStyle"
PageSize="10" AllowPaging="true" DataKeyNames="PullRequestId, RunDate"
OnPageIndexChanging="gvApsimFiles_PageIndexChanging"
OnRowCommand="gvApsimFiles_RowCommand"
OnRowDataBound="gvApsimFiles_RowDataBound"
OnSelectedIndexChanged="gvApsimFiles_SelectedIndexChanged" >
<HeaderStyle CssClass="GridViewHeaderStyle" />
<Columns>
<asp:BoundField DataField="PullRequestId" HeaderText="Pull Request Id" ItemStyle-Width="100px" />
<asp:BoundField DataField="RunDate" HtmlEncode="false" HeaderText="Run Date" ItemStyle-Width="220px" DataFormatString="{0:d MMMM, yyyy hh:mm tt}" />
<asp:BoundField DataField="IsMerged" HeaderText="Is Merged" ItemStyle-Width="100px" />
<asp:BoundField DataField="PercentPassed" HtmlEncode="false" HeaderText="Percent<br />Passed" ItemStyle-HorizontalAlign="Right" ItemStyle-Width="100px" />
<asp:BoundField DataField="Total" HeaderText="Total Files" ItemStyle-HorizontalAlign="Right" ItemStyle-Width="100px" />
<asp:ButtonField ButtonType="Button" ItemStyle-Font-Size="11px" Text="Accept Stats" CommandName="AcceptStats" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnAcceptStats" runat="server" Text="Accept Stats"
CommandName="AcceptStats"
CommandArgument='<%# Container.DataItemIndex %>'
OnClick="btnAcceptStats_Click"
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
In the code behind:
protected void btnAcceptStats_Click(object sender, EventArgs e)
{
GridViewRow gvRow = (GridViewRow)(sender as Control).Parent.Parent;
int index = gvRow.RowIndex;
int pullRequestId = int.Parse(gvApsimFiles.Rows[index].Cells[0].Text);
//Now we can call our web api 'merge' call
bool mergeStatus = bool.Parse(gvApsimFiles.Rows[index].Cells[2].Text);
if (!mergeStatus)
{
UpdatePullRequestMergeStatus(pullRequestId, true);
}
}
protected void gvApsimFiles_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gvApsimFiles.PageIndex = e.NewPageIndex;
BindApsimFilesGrid();
}
protected void gvApsimFiles_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "AcceptStats")
{
var eVal = Convert.ToInt32(e.CommandArgument);
int index = int.Parse(eVal.ToString());
int pullRequestId = int.Parse(gvApsimFiles.Rows[index].Cells[0].Text);
//Now we can call our web api 'merge' call
bool mergeStatus = bool.Parse(gvApsimFiles.Rows[index].Cells[2].Text);
if (!mergeStatus)
{
UpdatePullRequestMergeStatus(pullRequestId, true);
}
}
}
protected void gvApsimFiles_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Show as green if 100%
if (e.Row.Cells[3].Text.Equals("100"))
{
e.Row.ForeColor = Color.Green;
}
//Activate the row click event
e.Row.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(gvApsimFiles, "Select$" + e.Row.RowIndex);
e.Row.Attributes["style"] = "cursor:pointer";
}
}
Is there a way that I can have a button, that is only displayed when required, doesn't re-appear on postback, and triggers correctly, while maintaining the row click event?
If you want to hide buttons, why not base their visibility on a value of the GridView inline.
<asp:Button ID="Button2" runat="server" Visible='<%# Convert.ToBoolean(Eval("myBool")) %>' Text="Button 1" />
<asp:Button ID="Button1" runat="server" Visible='<%# !Convert.ToBoolean(Eval("myBool")) %>' Text="Button 2" />
Thanks for your response. I have the asp:Button displaying correctly with the following code:
visible='<%# Eval("IsMerged").ToString().ToLowerInvariant().Equals("false") %>'
The problem is that, when I use this button, I cannot get the Button Click event to work, only the row click event. When I step through the RowCommand the CommandName is only ever 'Select'. I am not able to trigger the 'AcceptStats' event.
I have found a solution. It is through the use of Gridview_RowDataBound, updating each cell in the grid, and then on the Gridview_RowCommand, retrieving these values, and going from there.
It is slightly slower to load, but works. The working code on the .aspx page is as follows:
<asp:GridView ID="gvApsimFiles" runat="server" AutoGenerateColumns="false" CssClass="GridViewStyle"
PageSize="10" AllowPaging="true" DataKeyNames="PullRequestId, RunDate"
OnPageIndexChanging="gvApsimFiles_PageIndexChanging"
OnRowCommand="gvApsimFiles_RowCommand"
OnRowDataBound="gvApsimFiles_RowDataBound" >
<HeaderStyle CssClass="GridViewHeaderStyle" />
<RowStyle CssClass="GridViewRowStyle" />
<Columns>
<asp:BoundField DataField="PullRequestId" HeaderText="Pull Request Id" ItemStyle-Width="100px" />
<asp:BoundField DataField="RunDate" HtmlEncode="false" HeaderText="Run Date" ItemStyle-Width="220px" DataFormatString="{0:d MMMM, yyyy hh:mm tt}" />
<asp:BoundField DataField="IsMerged" HeaderText="Is Merged" ItemStyle-Width="100px" />
<asp:BoundField DataField="PercentPassed" HtmlEncode="false" HeaderText="Percent<br />Passed" ItemStyle-HorizontalAlign="Right" ItemStyle-Width="100px" />
<asp:BoundField DataField="Total" HeaderText="Total Files" ItemStyle-HorizontalAlign="Right" ItemStyle-Width="100px" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="btnAcceptStats" runat="server" Text="Accept Stats"
Visible='<%# Eval("IsMerged").ToString().ToLowerInvariant().Equals("false") %>'
/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
with the code behind being:
protected void gvApsimFiles_RowCommand(object sender, GridViewCommandEventArgs e)
{
// Don't interfere with other commands.
// We may not have any now, but this is another safe-code strategy.
if (e.CommandName == "CellSelect")
{
// Unpack the arguments.
String[] arguments = ((String)e.CommandArgument).Split(new char[] { ',' });
// More safe coding: Don't assume there are at least 2 arguments.
// (And ignore when there are more.)
if (arguments.Length >= 2)
{
// And even more safe coding: Don't assume the arguments are proper int values.
int rowIndex = -1, cellIndex = -1;
bool canUpdate = false;
int.TryParse(arguments[0], out rowIndex);
int.TryParse(arguments[1], out cellIndex);
bool.TryParse(arguments[2], out canUpdate);
// Use the rowIndex to select the Row, like Select would do.
if (rowIndex > -1 && rowIndex < gvApsimFiles.Rows.Count)
{
gvApsimFiles.SelectedIndex = rowIndex;
}
//here we either update the Update Panel (if the user clicks only anything OTHER THAN our'Button'
//or we process the UpdatePullRequest as Merged
if (cellIndex == 5 && canUpdate == true)
{
int pullRequestId = int.Parse(gvApsimFiles.Rows[rowIndex].Cells[0].Text);
UpdatePullRequestMergeStatus(pullRequestId, true);
}
else
{
int pullRequestId = int.Parse(gvApsimFiles.Rows[rowIndex].Cells[0].Text);
BindSimFilesGrid(pullRequestId);
}
}
}
}
protected void gvApsimFiles_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Show as green if 100%
if (e.Row.Cells[3].Text.Equals("100"))
{
e.Row.ForeColor = Color.Green;
}
e.Row.Attributes["style"] = "cursor:pointer";
//Active cell click events on individual cells, instead of the row
foreach (TableCell cell in e.Row.Cells)
{
// Although we already know this should be the case, make safe code. Makes copying for reuse a lot easier.
if (cell is DataControlFieldCell)
{
int cellIndex = e.Row.Cells.GetCellIndex(cell);
bool canUpdate = false;
// if we are binding the 'Button' column, and the "IsMerged' is false, then whe can Update the Merge Status.
if (cellIndex == 5 && e.Row.Cells[2].Text.ToLower().Equals("false"))
{
canUpdate = true;
}
// Put the link on the cell.
cell.Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(gvApsimFiles, String.Format("CellSelect${0},{1},{2}", e.Row.RowIndex, cellIndex, canUpdate));
// Register for event validation: This will keep ASP from giving nasty errors from getting events from controls that shouldn't be sending any.
Page.ClientScript.RegisterForEventValidation(gvApsimFiles.UniqueID, String.Format("CellSelect${0},{1},{2}", e.Row.RowIndex, cellIndex, canUpdate));
}
}
}
}

Unable to persist data in GridView

have a GridView but cannot retrieve any of the data on post-back. I have set a break point at the start of Page_Init and Page_Load, on any post-back that is triggered the GridView.Rows.Count property is always 0. The GridView is defined as shown below:
<asp:GridView ID="TestGrid" runat="server" AllowSorting="False" DataKeyNames="ID,stock,percentage"
OnRowDataBound="GridViewTest_RowDataBound" EnableViewState="True"
OnRowUpdating="GridViewTest_OnRowUpdating" OnRowEditing="GridViewTest_OnRowEditing" OnRowCancelingEdit="GridViewTest_OnRowCancelingEdit"
AutoGenerateColumns="False">
<Columns>
<asp:CommandField ShowEditButton="True" CausesValidation="False"/>
<asp:BoundField DataField="Client" HeaderText="Client" InsertVisible="False" ReadOnly="True" />
<asp:BoundField DataField="Stock" HeaderText="Stock" InsertVisible="False" ReadOnly="True" />
<asp:BoundField DataField="DutyStatus" HeaderText="DutyStatus" InsertVisible="False" ReadOnly="True" />
<asp:TemplateField HeaderText="Percentage" InsertVisible="False">
<ItemTemplate>
<asp:Label ID="enhLbl" runat="server"><%#Eval("Percentage")%></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="TbPercentage" runat="server" Text="<%#Bind("Percentage")%>" class="edit-field"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I have a check for IsPostBack in Page_Load and only bind the GridView to its DataSource if it's not a post-back.
The only other time it gets re-bound is in the GridViewTest_OnRowEditing, GridViewTest_OnRowUpdating and GridViewTest_OnRowCancelingEdit event handlers.
I am binding the GridView to a DataTable in the following way:
AGridView.DataSource = DataTableSplitParcels;
AGridView.DataBind();
AGridView.EnableViewState = true;
I don't know if it makes any difference, but the DataTable is created in code and the rows added within a loop.
Within Page_Load on a post-back I can see the GridView has its DataKeysArrayList property populated with the current values, however with it having no rows I am unable to retrieve any updated values.
The problem seems in the Page_Load event, which is refreshing your GridView with every call (irrespective of postback), and because of that you are losing what was entered by the user during update.
So put a debugger on your Page_Load and BindData events and see if it is getting called by Page_Load at all, and you need to stop that.. I tried a sample app and it worked at my end.. see below the code that I tried.
ASPX
<asp:GridView ID="TaskGridView" runat="server"
AutoGenerateEditButton="True"
AllowPaging="true"
OnRowEditing="TaskGridView_RowEditing"
OnRowCancelingEdit="TaskGridView_RowCancelingEdit"
OnRowUpdating="TaskGridView_RowUpdating"
OnPageIndexChanging="TaskGridView_PageIndexChanging">
</asp:GridView>
CS
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// Create a new table.
DataTable taskTable = new DataTable("TaskList");
// Create the columns.
taskTable.Columns.Add("Id", typeof(int));
taskTable.Columns.Add("Description", typeof(string));
taskTable.Columns.Add("IsComplete", typeof(bool));
//Add data to the new table.
for (int i = 0; i < 20; i++)
{
DataRow tableRow = taskTable.NewRow();
tableRow["Id"] = i;
tableRow["Description"] = "Task " + i.ToString();
tableRow["IsComplete"] = false;
taskTable.Rows.Add(tableRow);
}
//Persist the table in the Session object.
Session["TaskTable"] = taskTable;
//Bind data to the GridView control.
BindData();
}
}
protected void TaskGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
//Retrieve the table from the session object.
DataTable dt = (DataTable)Session["TaskTable"];
//Update the values.
GridViewRow row = TaskGridView.Rows[e.RowIndex];
dt.Rows[row.DataItemIndex]["Id"] = ((TextBox)(row.Cells[1].Controls[0])).Text;
dt.Rows[row.DataItemIndex]["Description"] = ((TextBox)(row.Cells[2].Controls[0])).Text;
dt.Rows[row.DataItemIndex]["IsComplete"] = ((CheckBox)(row.Cells[3].Controls[0])).Checked;
//Reset the edit index.
TaskGridView.EditIndex = -1;
//Bind data to the GridView control.
BindData();
}
private void BindData()
{
TaskGridView.DataSource = Session["TaskTable"];
TaskGridView.DataBind();
}
Source available here

Row Deleting event of a child gridview throwing exception in asp.net C#

I have searched a lot but couldn't find a solution to my problem.
With C#.Net, Asp.net 3.5 I have a 2 gridview controls in master child relation as following:
<asp:GridView ID="gridViewExistingSchedules"
runat="server" DataKeyNames="SchedulerId"
AutoGenerateColumns="false"
OnRowDataBound="gridViewExistingSchedules_RowDataBound"
OnRowCommand="gridViewExistingSchedules_RowCommand"
OnRowDeleting="gridViewExistingSchedules_RowDeleting">
<Columns>
<asp:TemplateField ItemStyle-Width="20px">
<ItemTemplate>
<asp:GridView
ID="gridViewSchedulerDetails"
runat="server"
AutoGenerateColumns="false"
DataKeyNames="SchedulerId">
<Columns>
<asp:BoundField DataField="DetailId" Visible="false" />
<asp:BoundField DataField="Survey" HeaderText="Survey" />
<asp:BoundField DataField="TimeDescription" HeaderText="Time" />
<asp:BoundField DataField="FromDate" HeaderText="From Date" />
<asp:BoundField DataField="ToDate" HeaderText="To Date" />
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="imgDelete" CommandArgument='<%# Bind("SchedulerId")%>' CommandName="Delete"
runat="server" ImageUrl="~/images/delete1.png" />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="imgEdit" CommandArgument='<%# Bind("SchedulerId")%>' CommandName="Edit"
runat="server" ImageUrl="~/images/edit.png" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</ItemTemplate>
<ItemStyle Width="20px"></ItemStyle>
</asp:TemplateField>
<asp:BoundField DataField="Frequency" HeaderText="Frequency" />
<asp:BoundField DataField="DayOfWeek" HeaderText="Day Of Week" />
<asp:BoundField DataField="Time" HeaderText="Time" />
<asp:BoundField DataField="NextRunOn" HeaderText="Next Run On" />
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="imgDelete" CommandArgument='<%# Bind("SchedulerId")%>' CommandName="Delete"
runat="server" ImageUrl="~/images/delete.png" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Parent/master gridview "gridViewExistingSchedules" displays scheduled items where as child gridview "gridViewSchedulerDetails" displays details of a scheduled item (like which items were scheduled etc.)
I want to add a functionality, where a row in detailed gridview (i.e. gridViewSchedulerDetails can be deleted/edited. I have following code which handles row_deleting and row_command events:
protected void gridViewExistingSchedules_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
int schedulerId = int.Parse(this.gridViewExistingSchedules.DataKeys[e.Row.RowIndex].Value.ToString());
GridView gvDetails = e.Row.FindControl("gridViewSchedulerDetails") as GridView;
gvDetails.RowCommand += new GridViewCommandEventHandler(gvDetails_RowCommand);
gvDetails.RowDeleting += new GridViewDeleteEventHandler(gvDetails_RowDeleting);
UICaller caller = new UICaller();
gvDetails.DataSource = caller.BindSchedulerDetails(schedulerId);
gvDetails.DataBind();
}
}
void gvDetails_RowCommand(object sender, GridViewCommandEventArgs e)
{
UIWriter writer = new UIWriter();
if (e.CommandName.Equals("Delete"))
{
int surveyDetailId = int.Parse(e.CommandArgument.ToString());
if (writer.RemoveSurvey(surveyDetailId))
{
this.labelUserNotification.Text = "Deleted successfully";
}
else
this.labelUserNotification.Text = "Due to some internal error, selected item cannot be deleted";
//bind existing scheduler
UICaller caller = new UICaller();
this.gridViewExistingSchedules.DataSource = caller.BindScheduler();
this.gridViewExistingSchedules.DataBind();
}
else if (e.CommandName.Equals("Edit"))
{
}
}
void gvDetails_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
}
With above given code there is run time exception:
"The GridView 'gridViewSchedulerDetails' fired event RowDeleting which wasn't handled."
First I thought that since being in parent/child relation master gridview need to handle the row_command event of child "gridViewSchedulerDetails" so I changed the code to:
void gvDetails_RowCommand(object sender, GridViewCommandEventArgs e)
{
}
void gvDetails_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
}
protected void gridViewExistingSchedules_RowCommand(object sender, GridViewCommandEventArgs e)
{
UIWriter writer = new UIWriter();
if (e.CommandName.Equals("Delete"))
{
int surveyDetailId = int.Parse(e.CommandArgument.ToString());
if (writer.RemoveSurvey(surveyDetailId))
{
this.labelUserNotification.Text = "Deleted successfully";
}
else
this.labelUserNotification.Text = "Due to some internal error, selected item cannot be deleted";
//bind existing scheduler
UICaller caller = new UICaller();
this.gridViewExistingSchedules.DataSource = caller.BindScheduler();
this.gridViewExistingSchedules.DataBind();
}
else if (e.CommandName.Equals("Edit"))
{
}
}
protected void gridViewExistingSchedules_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
}
But I am still getting same error given above.
Please advise how can I handle child gridview row delete even and what is actually happening here
You have specified that deleting event in your aspx code and that event handler is not there in your .cs file code that's why it creating problem. Either write a event handler like following.
void gridViewExistingSchedules_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
}
or remove following from your aspx code if you don't need that.
OnRowDeleting="gridViewExistingSchedules_RowDeleting"
Couple of things...
If you specify OnRowCommand="gridViewExistingSchedules_RowCommand" then technically this will catch the delete command too. therefore you can remove OnRowDeleting="gridViewExistingSchedules_RowDeleting" and catch it using a switch on command name. (see here http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.rowcommand%28v=vs.110%29.aspx)
That aside lets move on to the error.
The GridView 'gridViewSchedulerDetails' fired event RowDeleting which wasn't handled.
You are receiving this because the delete method is called on the gridview gridViewSchedulerDetails which is not being dealt with. You have 2 options to get rid of it.
Add an OnRowDeleting method to the child grid (gridViewSchedulerDetails) and handle that.
Add an OnRowCommand method to the child grid (gridViewSchedulerDetails) and handle that.
UPDATE
Just thought your image buttons contain the command name delete and edit... these are reserved for the events delete and edit and fire them respectively. As you are assigning different events in your databound this might be causing a conflict. Try changing the CommandName on your image buttons to del and ed in your child grid view and see if that helps.

Variables lost on postback in asp.net

I have a gridview with some data and I want to add a checkbox column which can choose multiple rows. By clicking on it I want to save an primary key of row and change css class of row.
Using this article(step 2) I created itemtemplate,added there a checkbox(specifying ID as TransactionSelector), and add a checkedChange() to it. There I only change a css class of row and add a row index to arraylist. But when I click button with event which show this list, it has no items.
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" >
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="TransactionSelector" runat="server"
oncheckedchanged="TransactionSelector_CheckedChanged" AutoPostBack="True" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="iTransactionsId" HeaderText="iTransactionsId"
SortExpression="iTransactionsId" />
<asp:BoundField DataField="mAmount" HeaderText="mAmount"
SortExpression="mAmount" />
<asp:BoundField DataField="vchTransactionType" HeaderText="vchTransactionType"
SortExpression="vchTransactionType" />
<asp:BoundField DataField="dtDate" HeaderText="dtDate"
SortExpression="dtDate" />
<asp:BoundField DataField="cStatus" HeaderText="cStatus"
SortExpression="cStatus" />
<asp:BoundField DataField="test123" HeaderText="test123"
SortExpression="test123" />
</Columns>
<RowStyle CssClass="unselectedRow" />
</asp:GridView>
</asp:Panel>
<asp:Panel ID="InfoPanel" runat="server" CssClass="infoPanel">
<asp:Button ID="ShowSelected" runat="server" Text="Button"
onclick="ShowSelected_Click" />
<asp:Label ID="InfoLabel" runat="server"></asp:Label>
</asp:Panel>
C Sharp code:
public partial class WebForm1 : System.Web.UI.Page
{
ArrayList indices = new ArrayList();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
GridView1.DataSourceID = "SqlDataSource1";
GridView1.DataBind();
}
}
protected void TransactionSelector_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
GridViewRow row = (GridViewRow)cb.NamingContainer;
// row.CssClass = (cb.Checked) ? "selectedRow" : "unselectedRow";
if (cb.Checked)
{
row.CssClass = "selectedRow";
indices.Add(row.RowIndex);
}
else
{
row.CssClass = "unselectedRow";
indices.Remove(row.RowIndex);
}
}
protected void ShowSelected_Click(object sender, EventArgs e)
{
InfoLabel.Text = "";
foreach (int i in indices)
{
InfoLabel.Text += i.ToString() + "<br>";
}
}
}
}
You have to persist variable in postback using ViewState. Also its better if you use List<T> generic implementation rather than ArrayList
ViewState["Indices"] = indices;
And to recover it back
indices = ViewState["Indices"] as ArrayList;
As Habib said, you could use ViewState. You could also use ControlState instead, as shown here. If your code is in a custom control or user control, you may also need to override OnInit to
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Page.RegisterRequiresControlState(this);
}
Please feel free to respond with feedback. I'm new at posting answers.

Gridview with Enable and Disable image buttons

I have gridview in an asp.net application. I want to insert a column with image buttons where by click on it will enable or disable users or change the status field in db and also change the image button image accordingly user status.
Meaning: I want to display different images for disabled and enabled users.
How can I do this in C# and bind the data to the image button?
Anyone please help. Thanks in advance.
Make use of the ItemDataBound event. This is where you can check each row of your grid and apply changes to it. Then you can hide / unhide or change buttons:
VB.net below but you can easily convert to C#:
Dim ib As ImageButton = CType(e.Item.FindControl("ibFav"), ImageButton)
ib.Visible = False
Dim ib2 As ImageButton = CType(e.Item.FindControl("ibRemFav"), ImageButton)
ib2.Visible = True
Sample User Model:
public class UserModel {
public string Name { get; set; }
public bool IsEnabled { get; set; }
}
Here is the GridView Code:
<asp:GridView ID="GridView" runat="server" AutoGenerateColumns="false"
onrowcommand="GridView_RowCommand" onrowdatabound="GridView_RowDataBound">
<Columns>
<asp:TemplateField>
<ItemStyle HorizontalAlign="Center" />
<ItemTemplate>
<asp:ImageButton ID="EnabledImgBtn" runat="server"
CommandArgument='<%# Eval("Name") %>'
CommandName="ResetUserState" />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
//Other columns....
</Columns>
</asp:GridView>
Set the 'CommandArgument' according to your needs. e.g the ID of the User.
Sample Code-behind for the gridview:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack){
LoadGridView();
}
}
private void LoadGridView()
{
this.GridView.DataSource = GetUsersFromDatabase();
this.GridView.DataBind();
}
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var user = e.Row.DataItem as UserModel;
var enabledImgBtn = e.Row.FindControl("EnabledImgBtn") as ImageButton;
if (enabledImgBtn != null)
enabledImgBtn.ImageUrl = user.IsEnabled ? "~/YourImagePath/enabled.png"
: "~/YourImagePath/disalbed.png";
}
}
protected void GridView_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "ResetUserState")
{
if (e.CommandArgument!= null)
{
var userName = e.CommandArgument.ToString();
//Change user enabled state and Update database
//Sample code:
var user = FindUserByName("userName");
user.IsEnabled = !user.IsEnabled;
//SaveInDatabase(user);
LoadGridView();
}
}
}
You may consider using 'CommandField' with Type equal to 'Image' instead of 'TemplateField', but there is an issue with this approach, read more.
Hope this helps.
<asp:GridView ID="GridView" runat="server" AutoGenerateColumns="false"
onrowcommand="GridView_RowCommand" onrowdatabound="GridView_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="Change Status" ItemStyle-CssClass="GrdItemImg">
<ItemTemplate>
<asp:ImageButton ID="ibtnChangeActiveStatus" CommandArgument='<%#Eval("RecordID")%>'
CommandName='GRDSTATUS' runat="server" ImageUrl='<%# getStatusImage(Convert.ToInt32(DataBinder.Eval(Container.DataItem,"IsApproved"))) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Col2" HeaderText="Col2" />
//Other Respective columns....
...........
..........
</Columns>
</asp:GridView>
And In CS file add the following function.
public string getStatusImage(int intStatus)
{
string strStatus = string.Empty;
if (intStatus == 1)
{
strStatus = "~/images/active.png";
}
else
{
strStatus = "~/images/inactive.png";
}
return strStatus;
}
So on the base of "intStatus" respective active / InActive Image will be set.

Categories

Resources