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));
}
}
}
}
I am trying to hide the Telerik RadGrid Edit column until the user clicks on the row the user wants to edit. Upon the click event I need the Edit hyperlink column set to Visible="true". I was hoping to set the column as Visible="false" by default, and then add a click event in my .cs page to alter the visibility property, but I cannot figure out how to target the edit column... Here is my code for the .aspx page.
<telerik:RadGrid ID="RG_POI" runat="server" OnPreRender="RG_POI_PreRender" OnItemDataBound="RG_POI_ItemDataBound" >
<MasterTableView EditMode="InPlace" >
<Columns>
<telerik:GridEditCommandColumn Visible="false"/>
</Columns>
<EditFormSettings>
<EditColumn FilterControlAltText="Filter EditCommandColumn1 column" UniqueName="EditCommandColumn1">
</EditColumn>
</EditFormSettings>
</MasterTableView>
You can do this via C# or JavaScript. If you use C#, you can remove the OnRowSelected="gridSelected" from the grid definition below; if you use JavaScript then remove the OnSelectedIndexChanged="rgTest_SelectedIndexChanged":
ASPX:
<telerik:RadGrid ID="RG_POI" ... OnSelectedIndexChanged="rgTest_SelectedIndexChanged">
<ClientSettings ... >
<ClientEvents OnGridCreated="gridCreated" OnRowSelected="gridSelected" />
</ClientSettings>
<MasterTableView ... >
<Columns>
<telerik:GridEditCommandColumn UniqueName="Edit" />
...
Option 1) C#:
protected void rgTest_SelectedIndexChanged(object sender, EventArgs e)
{
RG_POI.Columns[1].Visible = true;
}
Option 2) JavaScript:
function gridCreated(menu, args) {
var radGrid = $find('RG_POI');
var table = radGrid.get_masterTableView();
table.shideColumn(1);
}
function gridSelected(menu, args) {
var radGrid = $find('RG_POI');
var table = radGrid.get_masterTableView();
table.showColumn(1);
}
Hi and thanks in advance.
I have a gridview that has four columns. The fourth column is hidden or displayed based on a set of criteria which is working correctly. But when the table displays, the very first cell in that last column is not showing any text, even though on databound it clearly shows that it has the text. So the gridview winds up showing data like this:
Name Address Zip Code
X H. Smith 123 Raton Ave.
X A. Rally 345 6th St 98453
X B. Holcomb 876 Harrison Blvd 56321
The OnRowDataBound looks like this:
protected void gvAddresses_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//This test evaluation string showed the correct data for every row
//string myvalue = DataBinder.Eval(e.Row.DataItem, "ZipCode").ToString();
if (user.State == (int)States.California)
gvAddresses.Columns[3].Visible = true;
}
}
There doesn't seem to be any problem with the binding and when I debug through the gridview each row is processed as I would expect. Here is the gridview:
<asp:GridView runat="server" ID="gvAddresses" CssClass="TableFormat gvMargin" Width="100%" AutoGenerateColumns="false"
OnRowCommand="gvAddresses_OnRowCommand" OnRowDeleting="gvAddresses_OnRowDeleting" OnRowDataBound="gvAddresses_OnRowDataBound">
<EmptyDataTemplate>
<div style="text-align: center;">No addresses available.</div>
</EmptyDataTemplate>
<Columns>
<asp:TemplateField HeaderText="" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:LinkButton ID="lnkRemoveAddress" runat="server" OnClientClick="if(!confirm('Are you sure you want to delete this record?')) return ;" style="color: maroon; font-weight: bold;" Text="X" CommandName="Delete" CommandArgument='<%# Eval("AddressCode") %>'></asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="Address" HeaderText="Address" />
<asp:BoundField DataField="ZipCode" HeaderText="Zip Code" Visible="False"/>
</Columns>
</asp:GridView>
How else can I discover what is happening to this first cell?
First problem is this: you are checking every individual row and setting the entire column to visible or not over and again. You should check for State before you databind, since it is the user object I would suggest doing it on preinit.
I suggest you remove the visible=false from your markup. When you set visible to false then the control/object isn't rendered into the HTML. Your problem will most likely be fixed if you remove the visibility attribute from the markup and assign that value at the proper time in codebehind.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
if (!postback)
{
gvAddresses.Columns[3].Visible = User.State == (int)States.California;
}
}
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.
In my GridView I have columns called 'F Notes', 'P Notes' and a ImageColumn. After clicking on the ImageButton a popup opens showing the data in the 'F Notes' and 'P Notes'. Now my problem is I do not want the 'F Notes' and 'P Notes' columns to be shown in the background when the pop up opens. I want the data to be visible only in the popup. I know if I change Visible = false then the column will not be shown but when I do that the text in the pop up is not visible.
Below is my code for both HTML and aspx.cs:
<asp:BoundField DataField="FNotes" HeaderText="F Notes" Visible="False" SortExpression="FNotes" />
<asp:BoundField DataField="PNotes" HeaderText="P Notes" Visible="False" SortExpression="PNotes" />
<asp:TemplateField HeaderText="Notes">
<ItemTemplate>
<asp:ImageButton ID="btnShowPopup" runat="server" Visible='<%#true.Equals(Eval("notesVisible"))%>' ImageUrl="~/Images/Imgs.jpg" Height="30px" Width="30px" OnClick="Popup" />
</ItemTemplate>
</asp:TemplateField>
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
GridView1.Columns[2].Visible = true;
GridView1.Columns[3].Visible = true;
}
As "mshsayem" suggested("Get DataKey values in GridView RowCommand"), I believe that you could bypass the visibility problems by defining your "FNotes" and "PNotes" as DataKeys in your GridView.
Change DataKeyNames in your GridView too:
DataKeyNames="MrNumber,FNotes,PNotes"
Then in your "Popup" reference the previously defined DataKeys rather than getting the data from the cells themselves.
protected void Popup(object sender, EventArgs e) {
ImageButton btndetails = sender as ImageButton;
GridViewRow gvrow = (GridViewRow)btndetails.NamingContainer;
lblMrNumber.Text = (string)GridView1.DataKeys[gvrow.RowIndex]["MrNumber"];
lblMrNumber.Text = gvrow.Cells[6].Text;
txtFNotes.Text = (string)GridView1.DataKeys[gvrow.RowIndex]["FNotes"];
txtPNotes.Text = (string)GridView1.DataKeys[gvrow.RowIndex]["PNotes"];
this.GridView1_ModalPopupExtender.Show();
}