I'm using the following code to make the entire row of my gridview clickable:
protected void gridMSDS_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.Attributes["onmouseover"] = "this.style.cursor='pointer';this.style.textDecoration='underline';this.style.backgroundColor='#EEFF00'";
e.Row.Attributes["onmouseout"] = "this.style.textDecoration='none';this.style.backgroundColor='White'";
e.Row.Attributes["onclick"] = ClientScript.GetPostBackClientHyperlink(this.gridMSDS, "Select$" + e.Row.RowIndex);
}
}
Which works great, except now I want to add edit ability to the grid. This works, but when I have both the row clickable and editing functions turned on, clicking the "Edit" link button often fires the row click event and vice versa.
So, how can I keep row clickable, except for specified columns?
UPDATE:
Here's what I'm using.
Based on Justin's solution:
List<int> notClickable = new List<int>();
{
notClickable.Add(0);
notClickable.Add(2);
}
for(int i = 0; i < e.Row.Cells.Count; i++)
{
if (!notClickable.Contains(i))
{
e.Row.Cells[i].Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(this.gridMSDS, "Select$" + e.Row.RowIndex);
}
}
The trick is the register the click on the specific columns that need to be clickable. The code below assumes you know the indexes that should be clickable (in this case 0).
e.Row.Cells[0].Attributes["onclick"] = Page.ClientScript.GetPostBackClientHyperlink(this.gridMSDS, "Select$" + e.Row.RowIndex);
Related
I have created multiple linkbutton on same cell of gridview row. But it's click event is not firing. On click event, I have to get StudentID defined in RowDataBound of Gridview.
protected void gvStudent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//loop through the cell.
for (int j = 1; j < e.Row.Cells.Count; j++)
{
string[] arrLinks = null;
if (!string.IsNullOrEmpty(e.Row.Cells[j].Text.ToString()) && e.Row.Cells[j].Text.ToString() != " ")
{
arrLinks = e.Row.Cells[j].Text.Split(',');//Rahul-3495,Meera-2323
}
if (arrLinks != null)
{
for (int i = 0; i < arrLinks.Length; i++)
{
LinkButton btnLink = new LinkButton();
string StudentName= (arrLinks[i].Split('-').First()).ToString();//Rahul
string StudentID = (arrLinks[i].Split('-').Last()).ToString();//3495
btnLink.ID ="btn_" + StudentID;
btnLink.Text = StudentName + "<br>";
// btnLink.Click += new EventHandler(StudentButtonsclick);
btnLink.CommandName = "btnLink";
e.Row.Cells[j].Controls.Add(btnLink);
}
}
}
}
}
protected void gvStudent_RowCommand(sender s, GridViewCommandEventArgs e)
{
if (e.CommandName == "btnLink")
{ }
}
<asp:GridView ID="gvStudent" runat="server" AutoGenerateColumns="true"
CssClass="gridview_alter"
OnRowDataBound="gvStudent_RowDataBound" OnRowCommand="gvStudent_RowCommand">
</asp:GridView>
Ok, the problem is that controls that require events that are created "after" the page has been rendered cannot really be wired up. You would have to move the code to a earlier event. So you are free to add controls, but they will in "most" cases be rendered TOO LATE to have events attached. Thus when you click on the link button, nothing fires.
So there are two solutions I can think of that will work.
First, set the control to have a a post back URL, and include a parameter on that post back.
eg this:
Dim lnkBtn As New LinkButton
lnkBtn.Text = "<br/>L" & I
lnkBtn.ID = "cL" & I
lnkBtn.PostBackUrl = "~/GridTest.aspx?r=" & bv.RowIndex
If you put a PostbackUrl, then when you click on the button, the page will post back. However, the grid row events such as rowindex change, or row click event etc. will NOT fire. So, if you willing to have a parameter passed back to the same page as per above, then you can pass the 1-3 (or 1-N) values you have for each control.
Of course that means you now have a parameter on the web page URL (and users will see this). You of course simply pick up the parameter value on page load with the standard
Request.QueryString["ID"] or whatever.
However, another way - which I think is better is to simple wire up a OnClickClick() event in js, and thus do this:
I = 1 to N
Dim lnkBtn As New LinkButton
lnkBtn.Text = "<br/>L" & I
lnkBtn.ID = "cL" & I
lnkBtn.OnClientClick = "mycellclick(" & I & ");return false;"
Now in above note how I am passing "I" to the js routine. You would pass your 200, 300 or whatever value you want.
then you script will look like this:
<script>
function mycellclick(e) {
__doPostBack("MySelect", e);
}
</script>
So above simply takes the value passed from the cell click (and linkbutn), and then does the postback with a dopostback. I used "MySelect", and you can give that any name you want.
Now, in the on-load event, you can simply go like this:
If Request("__EVENTTARGET") = "MySelect" Then
Dim mypassvalue As String = Request("__EVENTARGUMENT").ToString
Debug.Print("row sel for MySelect = " & mypassvalue)
End If
So, you are 100% correct - clicking on those controls does NOT fire server side event, and they are wired up too late for this to occur. so you can and often do say add some columns or controls to a gridview, but they are created and rendered TOO LATE for the events to be wired up (and thus they don't fire when clicked on).
But, you can add a postback to the lnkbutton, and you can also add a OnClickClick() event (JavaScript function call) and they will both work. I don't like parameters in the URL appearing when you click, so I think the js script call as per above works rather nice.
So while in the comments I noted (and suggested) that you have to set the CommandName="Select". This suggesting still holds true (without CommandName = select, then the rowindex will not fire. You can't use just ANY name - it MUST be select. However this ONLY works if the control is part of the grid and not added on the fly. As noted, it might be possible to move the grid event to "earlier" event (page initialize) but it going to be a challenge and will require you to re-organize the page. The most clean, and one that does not require parameters in the URL is adding that js OnClientClick() event. You can however set the controls postbackurl and along with a parameter in the URL, and that also can work well if you open to URL with parameters (I don't like them).
I would recommend using CommandName and OnRowCommand event for GridView. Here is how you should do it:
protected void gvStudent_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//loop through the cell.
for (int j = 1; j < e.Row.Cells.Count; j++)
{
string[] arrLinks = null;
if (!string.IsNullOrEmpty(e.Row.Cells[j].Text.ToString()) && e.Row.Cells[j].Text.ToString() != " ")
{
arrLinks = e.Row.Cells[j].Text.Split(',');//Rahul-3495,Meera-2323
}
if (arrLinks != null)
{
for (int i = 0; i < arrLinks.Length; i++)
{
LinkButton btnLink = new LinkButton();
string StudentName= (arrLinks[i].Split('-').First()).ToString();//Rahul
string StudentID = (arrLinks[i].Split('-').Last()).ToString();//3495
btnLink.ID = "btn_" + StudentID; // Good to concatenate a string instead just a number in the ID.
btnLink.Text = StudentName + "<br>";
btnLink.CommandName = "btnLink"; // Add a CommandName
e.Row.Cells[j].Controls.Add(btnLink);
}
}
}
}
}
protected void GridView1_RowCommand(sender s, GridViewCommandEventArgs e)
{
if (e.CommandName == "btnLink")
{
// Link Button was clicked.
var linkButton = (LinkButton)sender;
if (linkButton != null)
{
var studentId = linkButton.ID.Replace("btn_", ""); // Remove the concatenated string from the id.
// Do stuff with the student id.
// I would highly not recommend getting the id from a button element, as it could be modified using browser inspect elements. Instead use, GridView DataKeys.
}
}
}
You should add RowCommand event in your GridView as well to get it going. e.g:
<asp:GridView runat="server" ID="GridView1" OnRowCommand="GridView1_RowCommand">
<!-- Rest of the elements -->
</asp:GridView>
I created a user control which has datagridview. Then I added row and column dynamically from textfile in datagridview.
My problem is I need column which has buttons in each row. In first row, the text of button is 'Test1' and in second row 'Test2' not the same text.
After searched on google I tried this code
var testButton = new DataGridViewButtonColumn();
testButton.Name = "Test";
testButton.HeaderText = "Test";
testButton.UseColumnTextForButtonValue = true;
testButton.Text = "Test1";
this.dataGridView1.Columns.Add(testButton);
But it gives me both button text as 'Test1'.
Assuming you are in Windows Forms, you need to add a DataGridViewButtonColumn to your DataGridView - Not directly to the DataTable.
This should occur somewhere after you bind the DataTable to the DataGridView.
Something like this should work:
DataGridViewButtonColumn uninstallButtonColumn = new DataGridViewButtonColumn();
uninstallButtonColumn.Name = "uninstall_column";
uninstallButtonColumn.Text = "Uninstall";
int columnIndex = 2;
if (dataGridViewSoftware.Columns["uninstall_column"] == null)
{
dataGridViewSoftware.Columns.Insert(columnIndex, uninstallButtonColumn);
}
Of course you will have to handle the CellClick event of the grid to do anything with the button.
Add this somewhere in your DataGridView Initialization code
dataGridViewSoftware.CellClick += dataGridViewSoftware_CellClick;
Then create the handler:
private void dataGridViewSoftware_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == dataGridViewSoftware.Columns["uninstall_column"].Index)
{
//Do something with your button.
}
}
//Change the Button text property on a data-bound event
protected void YourDataGridViewId_RowDataBound(object sender, GridViewRowEventArgs e)
{
// finding the button control..`enter code here`.
if (e.Row.RowType == DataControlRowType.DataRow)
{
Button YourbtnVariable = (Button)e.Row.FindControl("YourbuttonID");
YourbtnVariable.Text = "Text"+e.Row.RowIndex+1;
//e.Row.RowIndex+1 will give u index of row every time incremented with 1
}
}
When I click on an item I would like to fill my TextBox with numbers from a column from Grid2 after Grid1 is clicked. Right now if I click on an item in Grid1 it will then run a procedure that will fill Grid2 with data. Here is an example of the current functionality with picture attached, I click an item from Grid1 and it has 3 results, my textbox will still display as an empty textbox. Then I click another item in Grid1 and now my textbox will display the 3 results from the previously clicked item. How can I display the correct numbers in my textbox after an item is selected in Grid1.
I have tried a few different methods including:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
divDetails.Visible = true;
RadTextBox1.Text = "";
for (int i = 0; i < Grid_Product_List_Details.Items.Count; i++)
{
RadTextBox1.Text += Grid_Product_List_Details.Items[i].GetDataKeyValue("number").ToString() + "\n";
}
}
and:
protected void Grid_Product_List_Details_PreRender(object sender, EventArgs e)
{
RadGrid grid = (RadGrid)sender;
if (grid.Items.Count > 0)
{
RadTextBox1.Text = "";
}
for (int i = 0; i < grid.Items.Count; i++)
{
RadTextBox1.Text += grid.Items[i].GetDataKeyValue("number").ToString() + "\n";
}
RadTextBox1.DataBind();
}
and this:
protected void Grid_Product_List_Header_SelectedIndexChanged(object sender, EventArgs e)
{
RadTextBox1.Text = "";
for (int i = 0; i < Grid_Product_List_Details.Items.Count; i++)
{
RadTextBox1.Text += Grid_Product_List_Details.Items[i].GetDataKeyValue("number").ToString() + "\n";
}
}
But those aren't working. Any suggestions?
Try to change your code a little bit.
RadTextBox1.Text = "";
foreach (GridDataItem dataItem in Grid_Product_List_Details.Items)
{
RadTextBox1.Text += dataItem.GetDataKeyValue("number").ToString() + "\n";
}
RadTextBox1.DataBind();
This should work though I suspect your earlier code should work too.
I ended up creating a procedure which fills the textbox after an item is clicked so the most recent data appears.
Try the ItemDataBound event of the second grid. You will have access to all of its data so you can put that in the RadTextBox. I suspect you provide a data source to the second grid in the SelectedIndexChanged of the first, so its Rebind() method should be called and then you will get the ItemDataBound fired for each of its rows.
Also, if you are using AJAX - disable it. It is possible that something does not get properly updated with the partial rendering. If things work fine with full postbacks, examine the responses and see why the textbox is not included in the first request so you can know how to tweak your AJAX setup.
I have a data source with an unknown number or rows and columns. I am using a grid view which is set to auto generate columns. I need to turn each item in each cell into a link button to post back for processing. I know how to dynamically add a control to a known row and cell but when i don't know the column name it makes it difficult. Any suggestions on how to do produce these results?
Try this as a starting point:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
foreach (TableCell cell in e.Row.Cells)
{
HyperLink myLink = new HyperLink();
myLink.NavigateUrl = "somewhere.aspx";
if (cell.Controls.Count > 0)
{
while (cell.Controls.Count > 0)
{
myLink.Controls.Add(cell.Controls[0]);
}
}
else
{
myLink.Text = cell.Text;
}
cell.Controls.Add(myLink);
}
}
}
Note: I've written the solution up in C#, as per your tag, but I notice your last comment is in VB. Let me know if you need me to re-post in VB (in which case you should update the tag).
I have a problem here regarding to editable gridview. what I want to do is replacing edit button function by using a single clickable row. When I click a row, it should be forwarding me to a new page for editing those row data. How can I achieve this, without using edit button?
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
// only apply changes if its DataRow
if (e.Row.RowType == DataControlRowType.DataRow)
{
// when mouse is over the row, save original color to new attribute, and change it to highlight yellow color
e.Row.Attributes.Add("onmouseover",
"this.originalstyle=this.style.backgroundColor;this.style.backgroundColor='#EEFF00'");
// when mouse leaves the row, change the bg color to its original value
e.Row.Attributes.Add("onmouseout",
"this.style.backgroundColor=this.originalstyle;");
}
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string abc = ((GridView)sender).DataKeys[e.Row.RowIndex].Value.ToString();
e.Row.Attributes["onClick"] = "location.href='Default.aspx?id=" + abc + "'";
//e.Row.Attributes["onClick"] = "location.href='Default.aspx?id=" + DataBinder.Eval(e.Row.DataItem, "CategoryID") + "'";
e.Row.Attributes.Add("style", "cursor:pointer;");
}
}
Simply add controls as you want to Default.aspx and on default.aspx pageload event(In not postback condition) retrieve the record through ID and populate the controls.
Now when submit button pressed update the record and redirect back to your original page