RadGrid Get Selected Row Index from Item Template Button - c#

I am working on a project using Telerik controls. I'm trying to figure out how to get the selected row index on an ItemTemplate button click event, like in the markup below:
<telerik:RadGrid ID="RadGrid1" runat="server" AllowFilteringByColumn="True"
DataSourceID="cusGrid" GridLines="None" Skin="Default" AllowPaging="True" DataKeyValue="CustomerID"
PageSize="500" AllowMultiRowSelection="True" ShowStatusBar="true" >
<MasterTableView AutoGenerateColumns="False" DataKeyNames="CustomerID" DataSourceID="cusGrid">
<RowIndicatorColumn>
<HeaderStyle Width="20px"></HeaderStyle>
</RowIndicatorColumn>
<ExpandCollapseColumn>
<HeaderStyle Width="20px"></HeaderStyle>
</ExpandCollapseColumn>
<Columns>
<telerik:GridTemplateColumn UniqueName="CheckBoxTemplateColumn">
<ItemTemplate>
<asp:Button runat="server" Text="Select" OnClick="SelRecord" />
</ItemTemplate>
</telerik:GridTemplateColumn>
...
Normally with a GridView I would just do something like:
protected void SelRecord(object sender, EventArgs e)
{
var gRow = (GridViewRow)(sender as Control).Parent.Parent;
var key = string.Empty;
if (gRow != null) { key = gRow.Cells[0].Text; }
}
What is the equivalent with the Telerik control?

Use the CommandArgument, and use OnCommand instead of OnClick to get the row index:
<asp:Button ID="Button1" runat="server" CommandArgument='<%#Container.ItemIndex%>' OnCommand="Button1_Command" ... />
Code-behind:
protected void Button1_Command(object sender, CommandEventArgs e)
{
GridDataItem item = RadGrid1.Items[(int)e.CommandArgument];
}

You can use CommandName="" instead of OnClick.
Also add onitemdatabound="RadGrid1_ItemDataBound" to the main telerik:RadGrid tag.
Then in the code behind:
protected void RadGrid1_ItemDataBound(object sender, GridItemEventArgs e)
{
if (e.Item is GridDataItem)
{
GridDataItem dataItem = e.Item as GridDataItem;
int selectedRowIndex = dataItem.RowIndex;
}
}

Looking through the Telerik documentation, it looks like you want:
var gRow = ((sender as Button).NamingContainer as GridItem).Selected;
You didn't ask about this piece, but I think this code:
if (gRow != null) { key = gRow.Cells[0].Text; }
is asking for trouble.
Although markup and code-behind are always highly coupled, directly referencing individual cells is a code smell if you ask me. I'm guessing that you want to pull "Select" out of the ASP Button in your ItemTemplate.
Can you assign an ID to your Button, and call FindControl("buttonID") to get the data you need? That will help keep your code more maintainable and readable.

<telerik:GridTemplateColumn UniqueName="IndexRow" HeaderText="#">
<ItemTemplate>
<%#Container.ItemIndex + 1%>
</ItemTemplate>
</telerik:GridTemplateColumn>

something like this in Button click event should work
foreach (GridDataItem item in RadGrid1.SelectedItems)
{
GridDataItem item = (GridDataItem)RadGrid1.SelectedItems;
var key = string.Empty;
key = item.ItemIndex;
}

Related

How can I get access to the button from code behind

How can I get access to the button from code behind using id "btnAutocomplete"?
<asp:GridView DataKeyNames="AutocompleteSchoolChild_Child" Width="1500px" CssClass="table table-bordered" OnDataBound="GridAutocomplete_OnDataBound"
ID="GridAutocomplete" runat="server" AutoGenerateColumns="false" AllowPaging="true" DataSourceID="sqlAutocomplete" Visible="true" PageSize="10"
OnSelectedIndexChanged="GridAutocomplete_OnSelectedIndexChanged">
<Columns>
<asp:TemplateField ItemStyle-HorizontalAlign="Center" ItemStyle-width="80px">
<ItemTemplate runat="server">
<asp:Button CssClass="btn btn-default" runat="server" ID="btnAutocomplete" Text="Зачислить" CommandName="Select"/>
</ItemTemplate>
</asp:TemplateField>
...
I assume that you want to change button text in currently selected row, so that you need to use FindControl with GridViewRow instance & cast it to a Button control:
protected void GridAutocomplete_OnSelectedIndexChanged(object sender, EventArgs e)
{
GridViewRow row = GridAutocomplete.SelectedRow;
Button btnAutocomplete = (Button)row.FindControl("btnAutocomplete");
btnAutocomplete.Text = "Insert"; // example to use button property
}
If you want to change button text in all GridView rows, you can use foreach loop together with GridViewRow instances on the same event handler:
foreach (GridViewRow row in GridAutocomplete.Rows)
{
if (row.RowType == DataControlRowType.DataRow)
{
Button btnAutocomplete = (Button)row.FindControl("btnAutocomplete");
btnAutocomplete.Text = "Insert"; // example to use button text property
}
}
If you're not sure that FindControl cast works properly, change all direct casts to as operator & use null checking like this:
GridViewRow row = (sender as GridView).NamingContainer as GridViewRow;
Button btnAutocomplete = row.FindControl("btnAutocomplete") as Button;
if (btnAutocomplete != null)
{
btnAutocomplete.Text = "Insert"; // example to use button text property
}
NB: The goal here is getting GridViewRow instance first before accessing button control inside TemplateField, so that SelectedRow is a proper way to get currently selected row.
Why don't you simply use GetElementById javascript method
document.getElementById("btnAutocomplete").innherHTML("");
Or jQuery:
("#btnAutocomplete").val = "";
As you've asked how to use this, I suggest that you add the code below after your HTML or your aspx layout code which you wrote in your question.
<script type="text/javascript">
//this function runs when the webpage is loaded
$(document).ready(function ()
{
document.getElementById("btnAutocomplete").innherHTML("whatever you want here");
//OR
("#btnAutocomplete").attr("style","whatever style html you want here");
});
//OR declare a private function which you can call through a click event
function buttonchange()
{
("#btnAutocomplete").val = "whatever value you want to give it";
}
</script>
You can assign the call event of the private function to some html element, for example:
<button type="button" class="btn" onclick="buttonchange()">Button changer</button>
i think you can define OnRowCommand for your gridview and define command name for your button,see this:
<asp:GridView DataKeyNames="AutocompleteSchoolChild_Child" Width="1500px" CssClass="table table-bordered" OnDataBound="GridAutocomplete_OnDataBound"
ID="GridAutocomplete" runat="server" AutoGenerateColumns="false" AllowPaging="true" DataSourceID="sqlAutocomplete" Visible="true" PageSize="10"
OnSelectedIndexChanged="GridAutocomplete_OnSelectedIndexChanged"
OnRowCommand="GridAutocomplete_RowCommand">
<Columns>
<asp:TemplateField ItemStyle-HorizontalAlign="Center" ItemStyle-width="80px">
<ItemTemplate runat="server">
<asp:Button CssClass="btn btn-default" runat="server" ID="btnAutocomplete" Text="Зачислить" CommandName="Select"/>
</ItemTemplate>
</asp:TemplateField>
and in code behind:
protected void grdSms_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.ToLower() == "select")
{
//do something
}
}

OnItemCommand Doesn't Work on Telerik Grid

I'm trying to create a Telerik grid where one of the columns contain a button that clicking it performs a certain action.
This is my definition of the grid in ASP:
<sq:Grid runat="server" CssClass="Master" ID="ReportGrid" DataSourceID="WorkPackageDS"
CellSpacing="0" GridLines="None" PageSize="100" AllowSorting="True" OnItemCommand="CancelWorkPackage_OnItemCommand"
AllowCustomPaging="True" AutoGenerateColumns="False" EnableViewState="False">
And this is the button I added:
<sq:GridTemplateColumn FilterImageToolTip="סינון" HeaderText="ביטול חבילת עבודה" UniqueName="btnCancelWO">
<ItemTemplate>
<asp:ImageButton runat="server" ID="btnCancel" ImageUrl="~/Shared Resources/imaes/tasksButton.png"
CommandName="CancelWO" CssClass="GridImageButton">
</asp:ImageButton>
</ItemTemplate>
</sq:GridTemplateColumn>
The "sq" is just something in my company, but it means a Telerik object.
This is my C# code of the function:
public void CancelWorkPackage_OnItemCommand(object sender, GridCommandEventArgs e)
{
if (e.CommandName == "CancelWO")
{
if (e.Item is GridDataItem)
{
GridDataItem gridDataItem = e.Item as GridDataItem;
string WFGUI = gridDataItem.FindControl("GUI").ToString();
int WorkflowInstanceId = Int32.Parse(gridDataItem.FindControl("fldIWfId").ToString());
RoadsManager.Instance.CancelWorkPackage(WFGUI, WorkflowInstanceId);
RoadsManager.Instance.LogCancellation(new[] { WorkflowInstanceId }, CurrentActivityId, CurrentUserId);
SignManager.Instance.DownloadPermitsFromSSRS(WorkflowInstanceId, WorkflowAPI.Instance.GetWorkflowVariable<object>(WorkflowInstanceId, "ReportName").ToString());
ShowAlert("חבילת עבודה ואישורים בוטלו בהצלחה", 400, 150, "הודעה חשובה");
}
}
}
I added breakpoint in the beginning of the C# function (on the if) and the program doesn't even enter the function.
What am I doing wrong?
Can anyone give me a tip what to change?
Thank you in advance
I changed the entire column from GridTemplateColumn to GridButtonColumn and now it works fine.

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