Grid view Edit issue - c#

I have editable grid view, If I click on edit in any row say "x", it opens in edit mode, however if I click on any other row, say "y", "x" should cancel edit. But In my code after clicking on "y", both the rows remains in edit mode.
protected void gvViewAdmins_RowEditing(object sender, GridViewEditEventArgs e)
{
gvViewAdmins.EditIndex = e.NewEditIndex;
Label lblEmailId = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvlblEmail") as Label;
lblEmailId.Visible = false;
ViewState["currentEmailId"] = lblEmailId.Text;
TextBox textboxEmailId = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvtbEmailId") as TextBox;
textboxEmailId.Text = ViewState["currentEmailId"].ToString();
textboxEmailId.Visible = true;
Label lblRole = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvlblRole") as Label;
lblRole.Visible = false;
ViewState["currentRole"] = lblRole.Text;
DropDownList dropdownRoles = gvViewAdmins.Rows[e.NewEditIndex].FindControl("gvddlRoles") as DropDownList;
this.PopulateRole(dropdownRoles);
dropdownRoles.Visible = true;
this.SelectRoleDropDownValue(dropdownRoles);
LinkButton lbtnUpdate = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnUpdate") as LinkButton;
LinkButton lbtnCancel = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnCancel") as LinkButton;
LinkButton lbtnEdit = gvViewAdmins.Rows[e.NewEditIndex].FindControl("lbtnEdit") as LinkButton;
lbtnUpdate.Visible = true;
lbtnCancel.Visible = true;
lbtnEdit.Visible = false;
}
What is wrong in my code?

After looking at your code, It seems that, you are not using gridview's default edit functionality. You are just setting controls visible property on and off.
Better way is, Define ItemTemplate and Edit Item Template Separately like,
Markup:
<asp:GridView ID="objGridView" runat="server" AutoGenerateColumns="false" onRowEditing="objGridView_RowEditing">
<columns>
<asp:TemplateField HeaderText="">
<ItemTemplate>
<asp:Label ID="lblEmailID" runat="server" Text='<%#Eval("<<EmailID Field>>")%>' />
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtEmailID" runat="server" Text='<%#Eval("<<EmailID Field>>")%>'/>
</EditItemTemplate>
</asp:TemplateField>
</columns>
</asp:GridView>
Code Behind:
protected void objGridView_RowEditing(object sender, GridViewEditEventArgs e)
{
objGridView.EditIndex = e.NewEditIndex;
<<BindGrid Again>>
}

Related

How to hide a link in a cell of a gridview?

I have a gridview which displays a data from the database. In one of the tables in this database have a column to store details about attanchment file. If the attachment is available that column value will set as "YES". Otherwise it will set as "NO". What I want to do is, show a link to view the attachment. But if cell value of the column is "NO" (when there is no attachment) the link must be hidden.
Note : I know how to view a file. Here what Im expecting is to hide the link in the cell which doesn't have an attachment.
This is what I have done upto now.
if (ds.Tables[0].Rows.Count > 0)
{
grdSo.DataSource = ds;
grdSo.DataBind();
for(int i=0; i <ds.Tables[0].Rows.Count; i++)
{
if (ds.Tables[0].Rows[i][6].Equals("NO"))
{
grdSo.Rows[i].Cells[6].Visible = false;
}
else
{
grdSo.Rows[i].Cells[6].Visible = true;
}
}
}
I could hide the cell using this code. But unfortunately this hides the lines of the cell too. How can I avoid it happening?
One of the ways to do this is to use server side control like LinkButton to view the link that you want to show and set the visibility of the control as per your requirement in the OnRowDataBound event of the gridview.
Below is the code to show/hide LinkButton on OnRowDataBound event.
protected void gridId_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataSourceClass varData = (DataSourceClass)e.Row.DataItem;
// check if your data have flag to show the link
if(varData.show)
((LinkButton)e.Row.FindControl("linkbuttonId")).Visible = true;
else
((LinkButton)e.Row.FindControl("linkbuttonId")).Visible = false;
}
}
ASPX Code :
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:BoundField Visible="false" DataField="id" />
<asp:TemplateField HeaderText="Has Attachment">
<ItemTemplate>
<asp:Label ID="lblAtt" runat="server" Text='<%#Eval("HasAtt") %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="View Attachment">
<ItemTemplate>
<asp:LinkButton ID="lbtnAtt" runat="server" OnClick="lbtnAtt_Click" Visible="false">View</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
CS Code :
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
this.BindGrid();
}
}
private void BindGrid()
{
//Here you write databind logic
// Datasource table of GridView1 should contain 'HasAtt' and 'id' as its binded to label.
}
private void ViewAttachment(int id)
{
//Here you write your logic to view attachment.
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow) // checking if row is datarow or not
{
Label lblHasAtt = e.Row.FindControl("lblAtt") as Label;
LinkButton lbtnViewAtt = e.Row.FindControl("lbtnAtt") as LinkButton;
lbtnViewAtt.Visible = (lblHasAtt.Text.ToLower() == "yes");
}
}
protected void lbtnAtt_Click(object sender, EventArgs e)
{
LinkButton lbtnViewAtt = sender as LinkButton;
GridViewRow grw = lbtnViewAtt.NamingContainer as GridViewRow;
int id = Convert.ToInt32(this.GridView1.Rows[grw.RowIndex].Cells[0].Text); // retriving value of first column on 'lbtnAtt' click row.
this.ViewAttachment(id);
}
I recall being able to parse through the grid view by using a for each for the rows and using a for statement for columns.
If I recall correctly, you can grab an item ie
row.Item[i]
foreach(GridViewRow row in GridView1.Rows)
{
for(int i = 0; i < GridView1.Columns.Count; i++)
{
// here you can do the logic to decide whether to show or hide the text for this cell
}
}
Sorry for formatting responding on my phone.

Get data from dynamically created controls in TemplateFields for gridview

I have a webpage that has a gridview which is bound to a list of custom objects but also has 1 dynamically created TemplateFields. These fields are created at Page_PreRender and can be a textbox or dropdownlist based on the object in the list. I have a button at the bottom of the page that needs to save all the data inputed in the dynamic objects when pressed. When i try to find the dynamic control i am unable to do so using the FindControl() method. It always comes back blank.
How can i retrieve the user entered/selected data?
This is my gridview
<div id="divSearchCriteriaGrid" runat="server" class="padding-top-15">
<asp:GridView ID="gvSearchCriteria" runat="server" AutoGenerateColumns="False" OnRowDataBound="gvSearchCriteria_OnRowDataBound" GridLines="None">
<Columns>
<asp:BoundField DataField="SearchFieldId" Visible="False" />
<asp:TemplateField HeaderText="Search Field">
<ItemTemplate>
<asp:CheckBox ID="cbDisplay" runat="server" AutoPostBack="False" onclick="ToggleCriteriaControls(this)" />
</ItemTemplate>
<ItemStyle Width="25%" />
</asp:TemplateField>
<asp:TemplateField HeaderText="Begin Criteria">
<ItemStyle Width="35%" />
</asp:TemplateField>
<asp:TemplateField HeaderText="End Criteria">
<ItemStyle Width="35%" />
</asp:TemplateField>
<asp:BoundField DataField="ControlTypeId" Visible="False" />
</Columns>
</asp:GridView>
</div>
And this is my code behind for creating the controls:
public void Page_PreRender(object sender, EventArgs e)
{
TryAction(PrepareLoad);
}
private void PrepareLoad()
{
if (IsPostBack) return;
BindData();
}
private void BindData()
{
gvSearchCriteria.DataSource = null;
gvSearchCriteria.DataSource = SearchFieldList;
gvSearchCriteria.DataBind();
}
protected void gvSearchCriteria_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
SearchField searchField = e.Row.DataItem as SearchField;
if (searchField != null)
{
e.Row.Cells[0].Text = searchField.SearchFieldId.ToString();
e.Row.Cells[4].Text = searchField.ControlTypeId.ToString();
CheckBox checkBox = (CheckBox)e.Row.FindControl("cbDisplay");
checkBox.Text = searchField.FieldDescription;
checkBox.Checked = searchField.Checked;
checkBox.Enabled = true;
if (searchField.ControlTypeId.ToString() == "1")
{
RadTextBox textBox = new RadTextBox();
textBox.ID = "txtBoxBegin";
e.Row.Cells[2].Controls.Add(textBox);
textBox = new RadTextBox();
textBox.ID = string.Format("txt{0}End", searchField.SearchFieldId);
e.Row.Cells[3].Controls.Add(textBox);
}
else if (searchField.ControlTypeId.ToString() == "2")
{
RadComboBox comboBox = new RadComboBox();
comboBox = new SearchService().GetRadComboBoxById(searchField.SearchFieldId);
comboBox.ID = string.Format("cbo{0}Begin", searchField.SearchFieldId);
e.Row.Cells[2].Controls.Add(comboBox);
}
}
}
}
This all works good and the controls get created with the checkbox.
Here is my code for trying to loop through each row of the gridview to get the user entered data which does not work.
private void Save()
{
foreach (GridViewRow row in gvSearchCriteria.Rows)
{
CheckBox include = (CheckBox)row.FindControl("cbDisplay");
int id, controlTypeId;
string criteriaOne = string.Empty;
string criteriaTwo = string.Empty;
if (!include.Checked) continue;
id = int.Parse(row.Cells[0].Text);
if (controlTypeId == "1")
{
RadTextBox radTextBox = (RadTextBox) row.FindControl("txtBoxBegin");
if (radTextBox != null)
{
criteriaOne = radTextBox.Text;
}
radTextBox = (RadTextBox)row.FindControl("txtBoxEnd");
if (radTextBox != null)
{
criteriaTwo = radTextBox.Text;
}
}
else if(controlTypeId == "2")
{
RadComboBox radComboBox = (RadComboBox)row.FindControl(string.Format("cbo{0}Begin",id));
if (radComboBox != null)
{
criteriaOne = radComboBox.SelectedValue;
}
}
}
}
The radTextBox and radComboBox variables i am trying to get using the FindControlId always comes back null.
cell 0 comes back ok each time with the correct Id. the cbDisplay checkbox always returns whether the row is checked or not and cell 4 gets the ControlTypeId just fine. It is the TemplateFields that i cannot get the values for.
Any help is greatly appreciated.
I was able to get the information from the dynamic controls once i moved the BindData() function to the Page_Init instead of the Page_PreRender().

GridView row won't disable

I am trying to disable a specific grdview row using the code below, but it isn't disabling that row. I am 100% sure there is a value called "Total Expenses" in the column that is bound to the gridview. What is more strange is that, I removed the if condition(accountTextBox.Text == "Total Expenses") to see if all the rows get disabled but only the first row is getting disabled. Any thoughts on this?
More information: Am using gridview with template fields(ASP.NET, C#). I also ran debugger and found that the accountTextBox is showing NULL. Am puzzled!
I appreciate any thoughts you may have. Thank you
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
if (!tableCopied)
{
originalDataTable = ((System.Data.DataRowView)e.Row.DataItem).Row.Table.Copy();
ViewState["originalValuesDataTable"] = originalDataTable;
tableCopied = true;
TextBox accountTextBox = (TextBox)e.Row.FindControl("AccountTextBox");
if (accountTextBox.Text == "Total Expenses")
{
e.Row.Enabled = false;
}
}
}
I'm assuming your markup looks something like this:
<asp:TemplateField HeaderText="SomeField" SortExpression="SomeField">
<EditItemTemplate>
<asp:TextBox ID="AccountTextBox" runat="server" Text='<%# Bind("SomeField") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("SomeField") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In which case AccountTextBox will only be available in RowDataBound when e.Row.State is in Edit mode. which may or may not be available depending what update functionality is provided in your datasource...but that's something else.
Typically you don't use a TextBox to display data but lets say trying to populate a "readonly" TextBox then all you need do is move AccountTextBox from the EditTemplate to the ItemTemplate and you should be good to go.
Using the following code-behind:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
gvTest.DataSource = new List<string>() { "test1", "test2" };
gvTest.DataBind();
}
private bool tableCopied = false;
private System.Data.DataTable originalDataTable;
protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
if (!tableCopied)
{
//originalDataTable = ((System.Data.DataRowView)e.Row.DataItem).Row.Table.Copy();
//ViewState["originalValuesDataTable"] = originalDataTable;
//tableCopied = true;
TextBox accountTextBox = (TextBox)e.Row.FindControl("AccountTextBox");
if (accountTextBox.Text == "Total Expenses")
{
e.Row.Enabled = false;
}
}
}
}
And this markup:
<asp:GridView runat="server" ID="gvTest" OnRowDataBound="gvTest_RowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="AccountTextBox" runat="server">Total Expenses</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
I am not reproducing the bug. Both rows disable for me.
The tableCopied variable could be the problem. It will be set to true on the first row and this will restrict the remaining rows to enter the if condition and actually be disabled.
First row:
//tableCopied is false
if(!tableCopied) // pass
tableCopied = true
Other rows:
//tableCopied is true
if(!tableCopied) // wont pass
Note that the GridView1_RowDataBound event occurs once for every row on the same postback and every class member is persisted during the postback.

Setting a Textbox value within a GridView template field

Within my load method of my page i want to set the Textbox in a templatefield to a value.
Here is my current source code showing my template field textbox item 'txtQuan':
<asp:TemplateField>
<ItemTemplate>
<asp:Label ID="lblTotalRate" Text="Qty:" runat="server" />
<asp:TextBox ID="txtQuan" Height="15" Width="30" runat="server" />
<asp:Button ID="addButton" CommandName="cmdUpdate" Text="Update Qty" OnClick="addItemsToCart_Click" runat="server" />
</ItemTemplate>
</asp:TemplateField>
And this is how im trying to set the TextBox value:
string cartQty = Qty.ToString();
((TextBox)(FindControl("txtQuan"))).Text = cartQty;
Im currently receiving a 'nullRefernceException error'.
Use the RowDataBound event to do that. You can look that up on the internet. The arguments to that event handler gives you easy access to each row. You can also loop through the rows using var rows = myGridView.Rows
var rows = myGridView.Rows;
foreach(GridViewRow row in rows)
{
TextBox t = (TextBox) row.FindControl("txtQuan");
t.Text = "Some Value";
}
For the event: GridView RowDataBound
protected void myGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
TextBox t = (TextBox) e.Row.FindControl("txtQuan");
t.Text = "Some Value";
}
}
((TextBox)grdviewId.Row.FindControl("txtQuan")).Text=cartQty;

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