DetailsView - Values not changing in ItemUpdating - c#

I have DetailsView binded to one object. When ItemUpdating is called (when I click update) OldValues is empty and NewValues contains old values (are the same as before update).
<asp:DetailsView ID="CustomerDetailsView" runat="server"
DefaultMode="Edit"
AutoGenerateRows="false"
OnItemUpdating="CustomerDetailsView_ItemUpdating"
>
<Fields>
<asp:BoundField DataField="LastName" HeaderText="Last name" ReadOnly="True" />
<asp:BoundField DataField="FirstName" HeaderText="First name" ReadOnly="True" />
<%-- Other fields ... --%>
<asp:CommandField ShowEditButton="true" />
</Fields>
</asp:DetailsView>
Code behind:
private Customer customer;
protected void Page_Load(object sender, EventArgs e)
{
using (var context = new CustomersContext())
{
customer = context.Logins.First();
}
CustomerDetailsView.DataSource = new List<Customer>() { customer };
CustomerDetailsView.DataBind();
}
protected void CustomerDetailsView_ItemUpdating(object sender, DetailsViewUpdateEventArgs e)
{
// e.OldValues.Count == 0
// e.NewValues["FirstName"] - is same as taken from database
}

See this answer: OldValues collection in event "ItemUpdating" of DetailsView is always empty
It appears that this only works if you use the DataSourceID property bound to a data source control.

Stupid me, I was setting new DataSource every time the page was reloaded even if it was post-back.
Should be:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (var context = new CustomersContext())
{
customer = context.Logins.First();
}
CustomerDetailsView.DataSource = new List<Customer>() { customer };
CustomerDetailsView.DataBind();
}
}
Can't see OldValues but NewValues looks correct.

Related

Best way to load data from DB and show in GridView

I am newbie to the ASP.Net world and have a confusion on how to approach the below scenario.
In my application I have to fetch the data from the database when page is loaded and show this in a GridView. The table currently has around 1000 records with about 7 columns. But the data will keep growing.
Here is the code of how I am binding the data to the grid.
protected void Page_Load(object sender, EventArgs e)
{
var data = new AppsAuthData().GetAllUsers();
gridUsersInfo.DataSource = data;
gridUsersInfo.DataBind();
}
I came to know that on every post back above code is getting executed (which obviously is not good). So I added the following to that start of the function
if (IsPostBack)
return;
var data = new AppsAuthData().GetAllUsers();
gridUsersInfo.DataSource = data;
gridUsersInfo.DataBind();
Page Markup
<%# Page Language="C#" AutoEventWireup="true" MasterPageFile="~/Site.Master" CodeBehind="RemoveUsers.aspx.cs" Inherits="AppsAuth.Authencations.RemoveUsers" %>
This again has an issue that after Postbacks, GridView has nothing to show. So next I saved my results to the ViewState and on each post back i was retrieving/updating the ViewState.
But since data can be huge in some scenarios, so what are best options available to deal with such issues?
GridView snippet
<asp:GridView ID="gridUsersInfo" runat="server" Width="100%" ForeColor="#333333" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="false" OnSorting="UserInfo_Sorting" OnRowEditing="gridUsersInfo_RowEditing"
OnPageIndexChanging="gridUsersInfo_PageIndexChanging" AutoGenerateEditButton="True">
> <Columns>
<asp:BoundField DataField="USER_ID" ReadOnly="True" HeaderText="ID" SortExpression="USER_ID" />
<asp:BoundField DataField="USER_NAME" ReadOnly="False" HeaderText="User Name" SortExpression="USER_NAME" />
</Columns>
</asp:GridView>
protected void gridUsersInfo_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gridUsersInfo.PageIndex = e.NewPageIndex;
gridUsersInfo.DataBind();
}
Instead of putting everything on PageLoad. You can put a button and write the code to populate GridView in the click event of that button.
Using the asp.net control Gridview with pagination enabled will do this for you.
Check the following example:
HTML
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" AllowPaging="true"
OnPageIndexChanging="OnPageIndexChanging" PageSize="10">
<Columns>
<asp:BoundField ItemStyle-Width="150px" DataField="CustomerID" HeaderText="Customer ID" />
<asp:BoundField ItemStyle-Width="150px" DataField="ContactName" HeaderText="Contact Name" />
<asp:BoundField ItemStyle-Width="150px" DataField="City" HeaderText="City" />
<asp:BoundField ItemStyle-Width="150px" DataField="Country" HeaderText="Country" />
</Columns>
</asp:GridView>
CodeBehind
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.BindGrid();
}
}
private void BindGrid()
{
string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand("SELECT CustomerId, ContactName, City, Country FROM Customers"))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
}
}
}
Implementing Pagination
The event handler is called when the page is changed inside the GridView.
The value of the PageIndex of the Page which was clicked is present inside the NewPageIndex property of the GridViewPageEventArgs object and it is set to the PageIndex property of the GridView and the GridView is again populated by calling the BindGrid function.
protected void OnPaging(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
GridView1.DataBind();
}
Source : http://www.aspsnippets.com/Articles/Paging-in-ASPNet-GridView-Example.aspx
What you have to do is just bind bind gridview when !IsPostback in page_load
if(!IsPostBack)
{ var data = new AppsAuthData().GetAllUsers();
ViewState["UserData"] = data;
gridUsersInfo.DataSource = data;
gridUsersInfo.DataBind();
}
Hear is an example : Asp.Net Bind Grid View
In .aspx file
<form runat="server" onload="Page_Load">
<asp:GridView runat="server" ID="gridEvent" AutoGenerateColumns="False" BackColor="White"
BorderStyle="None" BorderWidth="0px" class="table mb-0"
>
<RowStyle BackColor="White" />
<Columns>
<asp:BoundField DataField="EventId" HeaderText="#" />
<asp:BoundField DataField="Title" HeaderText="Event Title" />
<asp:BoundField DataField="EventDate" HeaderText="Event Date" />
<asp:BoundField DataField="Location" HeaderText="Venue" />
<asp:BoundField DataField="RegisteredUsers" HeaderText="Registred User(s)" />
<asp:CommandField ShowEditButton="True" />
<asp:CommandField ShowDeleteButton="True" />
</Columns>
<FooterStyle BackColor="#99CCCC" ForeColor="#003399" />
<PagerStyle BackColor="#99CCCC" ForeColor="#003399" HorizontalAlign="Left" />
<SelectedRowStyle BackColor="#009999" Font-Bold="True" ForeColor="#CCFF99" />
<HeaderStyle BackColor="#FBFBFB" Font-Bold="True" ForeColor="#5A6169" />
</asp:GridView>
</form>
in the .aspx.designer.cs
public partial class Default
{
/// <summary>
/// txtLocation control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.GridView gridEvent;
}
in the .aspx.cs file
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
// Enable the GridView paging option and
// specify the page size.
gridEvent.AllowPaging = true;
gridEvent.PageSize = 15;
// Initialize the sorting expression.
ViewState["SortExpression"] = "EventId ASC";
// Enable the GridView sorting option.
gridEvent.AllowSorting = true;
BindGrid();
}
}
private void BindGrid()
{
// Get the connection string from Web.config.
// When we use Using statement,
// we don't need to explicitly dispose the object in the code,
// the using statement takes care of it.
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["sqlConn"].ToString()))
{
// Create a DataSet object.
DataSet dsPerson = new DataSet();
// Create a SELECT query.
string strSelectCmd = "SELECT * FROM EventsList";
// Create a SqlDataAdapter object
// SqlDataAdapter represents a set of data commands and a
// database connection that are used to fill the DataSet and
// update a SQL Server database.
SqlDataAdapter da = new SqlDataAdapter(strSelectCmd, conn);
// Open the connection
conn.Open();
// Fill the DataTable named "Person" in DataSet with the rows
// returned by the query.new n
da.Fill(dsPerson, "EventsList");
// Get the DataView from Person DataTable.
DataView dvPerson = dsPerson.Tables["EventsList"].DefaultView;
// Set the sort column and sort order.
dvPerson.Sort = ViewState["SortExpression"].ToString();
// Bind the GridView control.
gridEvent.DataSource = dvPerson;
gridEvent.DataBind();
}
}
//Implementing Pagination
protected void OnPaging(object sender, GridViewPageEventArgs e)
{
gridEvent.PageIndex = e.NewPageIndex;
gridEvent.DataBind();
}

how to get boundfield value of a gridview in rowupdating event

i want to pick the databound field value. im getting compilation error saying doesnot contain a definatin for a Cells
<asp:GridView ID="gvBankDetails" runat="server" AutoGenerateColumns="false" AutoGenerateEditButton="true" OnRowEditing="gvBankDetails_RowEditing" OnRowCancelingEdit="gvBankDetails_RowCancelingEdit" OnRowUpdating="gvBankDetails_RowUpdating">
<Columns>
<asp:BoundField HeaderText="sl no" DataField="id" />
</Columns>
</Gridview>
protected void gvBankDetails_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string dtr = ((TextBox)gvBankDetails.Cells[0].Controls[0]).Text;
}
to get value of bound field in grid view
protected void gvBankDetails_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string strName = ((TextBox)gvBankDetails.Rows[e.RowIndex].Cells[3].Controls[0]).Text;
}
gvBankDetails.Rows[e.RowIndex].Cells[0].Text
index may be different based on column number

unable to update gridview values in .net

while updating gridview record . old values only getting updated. im using bound field. getting old value while im fetching data in variable.
<asp:GridView runat="server" ID="GvLeads" AutoGenerateColumns="false" AutoGenerateEditButton="true" AutoGenerateDeleteButton="true" OnRowDeleting="GvLeads_RowDeleting" OnRowEditing="GvLeads_RowEditing" OnRowCancelingEdit="GvLeads_RowCancelingEdit" EmptyDataText="No Records Found" OnRowUpdating="GvLeads_RowUpdating" OnRowDeleted="GvLeads_RowDeleted">
<Columns>
<asp:BoundField HeaderText="Id" DataField="LeadId" />
<asp:BoundField HeaderText="Company" DataField="Companyname" />
</Columns>
</GridView >
code behind
protected void GvLeads_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
GridViewRow row = GvLeads.Rows[e.RowIndex];
String str = ((TextBox)(row.Cells[1].Controls[0])).Text;
int Leadid = Convert.ToInt32(str);
string CompanyName = ((TextBox)(row.Cells[2].Controls[0])).Text;
}
This usually happens when you are populating grid at Page_Load as soon as RowUpdating event gets called before that Page_Load event get's called which populates the grid with initial values. How to Avoid? Use !IsPostBack for this purpose
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindGrid(); // For e.g.
}
}

GridView and DetailsView Code Behind to Update DetailsView

I've spent all afternoon trying to do this using CODE BEHIND without success so I am asking for some C# code.
Basically, I have a GV and a DV in a master/detail relationship. GV displays ID and Name. If I click Select on a GV row, I want to see its ID, Name and Address in DV. I know how get this to work declaratively in an aspx file. But in C# code behind, I don't know how to proceed at this function:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName.Equals("Select"))
{
// PLEASE GIVE ME THE CODE HERE TO BIND THE DETAILSVIEW. THANKS!
// I am using a sqldatasource if it makes any difference
}
}
Here's a general solution showing you how to achieve this, please note that this solution isn't extremely error-safe but I suppose you'll get the jist of it. Please comment if there's anything unclear.
Code-behind:
protected void gv_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Select")
{
GridViewRow selected = gv.Rows[Convert.ToInt32(e.CommandArgument)];
List<ThatClass> cList = new List<ThatClass>();
cList.Add(new ThatClass(selected.Cells[0].Text, selected.Cells[1].Text));
dv.DataSource = cList;
dv.DataBind();
}
}
Markup:
<asp:GridView ID="gv" runat="server" AutoGenerateColumns="false" OnRowCommand="gv_RowCommand">
<Columns>
<asp:BoundField DataField="A" HeaderText="A"/>
<asp:BoundField DataField="B" HeaderText="B" />
<asp:CommandField ShowSelectButton="true" />
</Columns>
</asp:GridView>
<asp:DetailsView runat="server" ID="dv">
</asp:DetailsView>
FYI: I bound the GV using a List:
protected void Page_Load(object sender, EventArgs e)
{
List<ThatClass> cList = new List<ThatClass>();
cList.Add(new ThatClass("123", "abc"));
cList.Add(new ThatClass("456", "def"));
gv.DataSource = cList;
gv.DataBind();
}

All GridView rows disappear while selecting a row

Please consider the values in comments which I got in debug mode:
protected void FilesGrid_SelectedIndexChanged(object sender, EventArgs e)
{
int selected = FilesGrid.SelectedIndex; // selected = 2
FilesGrid.DataBind(); //added after feedback in comments. it makes no change
int count = FilesGrid.Rows.Count; // count = 0
GridViewRow row = FilesGrid.Rows[selected]; // row = null
GridViewRow row0 = FilesGrid.Rows[0]; // row = null
}
I came to this code while investigating why SelectedValue gives null in this event handler (the DataKeyNames parameter was set for sure).
Can anybody explain how it is possible?
Thank you in advance.
PS.
Here is my aspx code:
<asp:GridView ID="FilesGrid" runat="server" AutoGenerateColumns="False"
AutoGenerateSelectButton="True"
onselectedindexchanged="FilesGrid_SelectedIndexChanged"
style="margin-top: 0px" >
<Columns>
<asp:CommandField ShowDeleteButton="True" />
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="Length" DataFormatString="{0:N0}"
HeaderText="Size in Bytes" HtmlEncode="False" />
</Columns>
</asp:GridView>
Here is how I bind data:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string [] dd = {"FullName"};
FilesGrid.DataKeyNames = dd;
string appPath = Request.PhysicalApplicationPath;
DirectoryInfo dirInfo = new DirectoryInfo(appPath);
FileInfo[] files = dirInfo.GetFiles();
FilesGrid.DataSource = files;
FilesGrid.DataBind(); }
}
Y copy pasted your code, delete this line FilesGrid.DataBind() in the FilesGrid_SelectedIndexChanged, i see that are 2 methods that you are not posting, that aren't in the code that you posted the onselectedindexchanging, onrowdeleting events, comment them from the aspx and see if it works, or se if that events are not doing something tricking, that are deleting the rows in your GridView.
Tell me if it works
I did this
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string[] dd = { "FullName" };
FilesGrid.DataKeyNames = dd;
string appPath = Request.PhysicalApplicationPath;
DirectoryInfo dirInfo = new DirectoryInfo(appPath);
FileInfo[] files = dirInfo.GetFiles();
FilesGrid.DataSource = files;
FilesGrid.DataBind();
}
}
protected void FilesGrid_SelectedIndexChanged(object sender, EventArgs e)
{
int selected = FilesGrid.SelectedIndex; // selected = 2
//FilesGrid.DataBind(); //added after feedback in comments. it makes no change
int count = FilesGrid.Rows.Count; // count = 0
GridViewRow row = FilesGrid.Rows[selected]; // row = null
GridViewRow row0 = FilesGrid.Rows[0]; // row = null
}
protected void FilesGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
}
protected void FilesGrid_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
}
The aspx code.
<asp:ScriptManager ID="ScriptManager1" runat="server" EnableScriptGlobalization="true"
AsyncPostBackTimeout="0" EnableScriptLocalization="true">
</asp:ScriptManager>
<asp:UpdatePanel ID="upPanel" runat="server">
<ContentTemplate>
<asp:GridView ID="FilesGrid" runat="server" AutoGenerateColumns="False" AutoGenerateSelectButton="True"
OnRowDeleting="FilesGrid_RowDeleting" OnSelectedIndexChanged="FilesGrid_SelectedIndexChanged"
Style="margin-top: 0px" OnSelectedIndexChanging="FilesGrid_SelectedIndexChanging">
<Columns>
<asp:CommandField ShowDeleteButton="True" />
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="Length" DataFormatString="{0:N0}" HeaderText="Size in Bytes"
HtmlEncode="False" />
</Columns>
</asp:GridView>
</ContentTemplate>
</asp:UpdatePanel>
remove the FilesGrid.DataBind(); //added after feedback in comments. it makes no change
When I add that statement to my code I am getting the error. after removing that please try again. If not working please share the
protected void FilesGrid_SelectedIndexChanging(object sender, GridViewSelectEventArgs e) method code, may be something wrong with that section
The issue was resolved by commenting out the line // if (!Page.IsPostBack). It looks like the data source is lost somehow during the postback. The whole seems to be a local bug with ViewState, because this behavior was not observed by other users. My special thanks to Tim Schmelter and naveen.
You can keep Page.IsPostBack in Page_Load, I was having the same issue and it turns out the grid was not in ViewState in my case. If you use Linq query in your controller you will want to add this property to the grid so it will keep refreshing properly:
<asp:Panel EnableViewState="True">

Categories