changing textbox value in code behind does not post back new value - asp.net

I have a gridview (ASP.NET Web Form project) with 4 columns in it: A CommandField for editing of the rows, and 3 TemplateField>EditItemTemplate>Textbox columns called Total_Plan, Mth_1 and Mth_2. The 3 textbox columns are bound to an SqlDataSource.
Total_Plan is defined as:
<asp:TemplateField HeaderText="Total Plan">
<EditItemTemplate>
<asp:TextBox ID="txbTotalPlan" runat="server" Text='<%# Bind("Total_Plan") %>'>
</asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="idNotUsedButNeeded0" runat="server" Text='<%# Bind("Total_Plan") %>' />
</ItemTemplate>
</asp:TemplateField>
When the user presses Edit, changes the values of Mth_1 or 2, then presses Update, the following code runs:
protected void gridDetail_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
double totPlan =0;
totPlan += double.Parse(((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbMth_1")).Text);
totPlan += double.Parse(((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbMth_2")).Text);
((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbTotalPlan")).Text = totPlan.ToString();
}
The values entered in Mth_1 and Mth_2 are then updated to to SQL, however, the value of Total_Plan does NOT get updated in the database. The line of code
((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbTotalPlan")).Text = totPlan.ToString();
does change the value of the textbox, because when I check ((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbTotalPlan")).Text I can see the NEW value assigned, however this assignment does not seem to be posted back to the server and so upon Updating the SQL table, the old value is preserved (I inspected the e.Command.Parameters[0].Value of the SqlDataSource_Updating event and indeed, the assignment I do programmatically to the textbox is not picked up when doing the Update to SQL.
I tried adding AutoPostBack=true on the txbTotalPlan but this did not work.
Why if I am doing an assignment, server side, to a textbox in a row of a grid, at the time the update is taking place (i.e. not After), the new value is not used for the Update operation? Am I doing this assignment too late? The alternative I thought was to make the assigmment to the Total Plan column in the OnTextChanged event of each Mth_1 and 2, but if I can write the assignment in a central place and only at a time before updating, it seems less messy and less frequent.
I put a stop in the protected void Page_Load(object sender, EventArgs e) event and indeed at the time of making the assigmment to the txbTotalPlan textbox, this method is not called.
Thank you for your help.

I still dont know about why this doesnt work in the grid's RowUpdating event, but the alternative solution I used was to do the assignment by subscribing to the OnUpdating event of the SqlDataSource and assigning as shown below.
protected void SqlData_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
//calculate Total Plan (sum of all mth columns)
double mth_AddedUp = 0;
foreach(System.Data.Common.DbParameter p in e.Command.Parameters)
if(p.ParameterName.Length > 5 &&
p.ParameterName.Substring(0,5)=="#Mth_" &&
p.Value != null)
mth_AddedUp += double.Parse(p.Value.ToString());
// set Plan parameter value
e.Command.Parameters["#Plan"].Value = (mth_AddedUp).ToString();
}

You are updating data using SqlDataSource. You need to update it's parameter rather than the textbox value. Do like this:
protected void gridDetail_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
double mth1=0;
double mth2=0;
mth1 = double.Parse(((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbMth_1")).Text);
mth2 = double.Parse(((TextBox)gridDetail.Rows[e.RowIndex].FindControl("txbMth_2")).Text);
yourDataSource.UpdateParameters["Mth_1"].DefaultValue = mth1;
yourDataSource.UpdateParameters["Mth_2"].DefaultValue = mth2;
yourDataSource.UpdateParameters["Total_Plan"].DefaultValue = mth1 + mth2;
yourDataSource.Update();//yourDataSource is your SqlDataSource
}

Related

Validation before inserting into Gridview

I am adding data in gridview but not using sql, and my question is i want to validate first if i already inserted the data in the gridview before inserting. searching every data in my gridview before inserting, is it possible?
It is possible, set asp:GridView ID="GridView1" OnRowCommand="GridView1_RowCommand" to this method, so when you click on insert it will execute this method, you can do the check before inserting:
Sample code:
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
string val= textBox1.Text();
\\check if the value already exists in the datasource you are binding to gridivew <br/>
if(! value exists)
\\ do the insert
}

How to edit gridview row inside?

I want to edit row of gridview.For that, I have added showeditbutton = true.I have binded gridview from cs file.Does I need to wite 3 function for that?(For editing I have added 3 function in cs file.).I have taken help from internet.But some point did not understand.
--In aspx
<asp:GridView datakeyname="Id" Id ="Gridview1" onRowEditing="GridView1_RowEditing" RowCancelingEdit=" GridView1_RowCancelingEdit" onRowUpdating ="GridView1_RowUpdating" >
<column>
// hyperlink ,dataTextfield is id
// some checkboxfield.(start from column 6)
</column>
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
//code for Binding grid
}
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
// for fetching value of id and checkboxfield(column 6)
string Id= GridView1.DataKeys[e.RowIndex].Values["Id"].ToString());
bool ischeck = (Gridview1.Rows[e.RowIndex].Cells[5].Controls[0] as checkBox).Checked;
// code for updating grid
GridView1.EditIndex = -1;
//Now bind the gridview gain here
}
protected void GridView1_RowCancelingEdit(object sender, GridViewUpdateEventArgs e)
{
GridView1.EditIndex = -1;
//Now bind the gridview gain here
}
Does am I going in right direction?What is use of datakey.Does I used properly?Why GridView1.EditIndex = -1 in update and cancel event.Column 6 is checkboxfield.why .Controls[0] is used for accessing that checkboxfield.
If you are using an ObjectDataSource (or SqlDataSource or OleDbDataSource) to databind and use UpdateCommand, DeleteCommand, InsertCommand, then you do not need to explicitly write those three functions for the edit/update operation. You need those functions when you are writing the binding code in code-behind or if you want to do additional work before/after any operation.
RowEditing fires when you click "edit" on the GridView. Here you specify what row to open in editmode by writing GridView1.EditIndex = e.NewEditIndex. You can also write code here to do any work that is required before user is put into editmode. For example, you can check for business rules conditions, and cancel the operation if rules are not met.
RowUpdating fires when you click "save"/"update" on the GridView. This is fired before the actual database operation. If you have an UpdateCommand on the datasource, then you do not need to write database save routine, otherwise you write that here.
DataKeys identify the "key" that identifies the data that is bound. You specify DataKeys while databinding to the GridView. For example, primary key of a database table. This line: string Id= GridView1.DataKeys[e.RowIndex].Values["Id"].ToString()); Here you are picking up the value of the "Id" key (you can have more than one keys) of the current row.
GridView1.EditIndex = -1 in update or cancel specifies that the GridView should no longer be in editmode. If this value is >= 0, then the GridView is put into editmode for that row (index starting from 0). So we set it to -1, to indicate that it should not be in editmode.
Controls[0] is used to pick the first control in that cell (you may have more than one controls). Alternatively, you can also use FindControl.

GridView Paging Issue

I am using a gridview control and performing Paging and Sorting manually.
Here is the method of Paging:
protected void gdvMainList_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
gdvMainList.PageIndex = e.NewPageIndex;
gdvMainList.DataSource = dtConsentReleaseList;
gdvMainList.DataBind();
}
I have a static datatable having a column Id:
dtConsentReleaseList.Columns.Add("Id");
dtConsentReleaseList.Columns.Add("StartDate");
dtConsentReleaseList.Columns.Add("EndDate");
dtConsentReleaseList.Columns.Add("Contact");
I am assigning datakeynames "Id" in my GridView.
And I also have a print button in each row. When I click that button, this code gets executed:
else if (e.CommandName == "New")
{
int selectedIndex = Convert.ToInt32(e.CommandArgument);
int consentReleaseId = Convert.ToInt32(gdvMainList.DataKeys[selectedIndex].Value);
string openReportScript = Utility.OpenReport(ResolveClientUrl("~/Reports/Consumer/ConsentReleaseReport.aspx?Id=" + consentReleaseId + "&ReportTitle=ConsentForRelease"));
ScriptManager.RegisterClientScriptBlock(upConsentRelease, upConsentRelease.GetType(), "Pop up", openReportScript, true);
}
but when I change the page and clicks print button, an exception occurs on this line :
int consentReleaseId = Convert.ToInt32(gdvMainList.DataKeys[selectedIndex].Value);
Exception is:
Index was out of range. Must be non-negative and less than the size of the collection.Parameter name: index
I guess I am doing something wrong in Paging method.
Any help please?
You are trying to get a value out of an array based on an arbitrary ID instead of the actual index. But you don't need to do that at all. You don't need to store your ID in the DataKeys and you don't need to access anything using the index of the item. Just pull your ID out from the CommandArgument.
<asp:ImageButton CommandName="New" CommandArgument='<%# Eval("Id") %>' ID="ibtnPrint" runat="server" ImageUrl="~/App_Themes/Default/images/print.png" />
And then in code-behind:
int consentReleaseId = int.Parse(e.CommandArgument);
My guess is that you bind the gridview in code-behind (possibly page_load event) and it doesn't hold the values on postback.
Also, try to pass the Id as CommandArgument. As far as I can tell, if you have access to Id of the selected record, you don't need grid's row index at all. (GridView passes row's index as CommandArgument by default)
Set the datakeyname right before you set the datasource and bind the gridview.
In addition,
string[] dk = new string[1] {"MyID"};
myGridView.DataKeyNames = dk;
myGridView.DataSource = ds;
myGridView.DataBind();

ASP ListView: How do I access the data that is databound to the rows?

I want to access the data that was databound to my list view when handling list view events such as:
protected void List_ItemDataBound(object sender, ListViewItemEventArgs e)
or
protected void List_ItemCommand(object sender, ListViewCommandEventArgs e)
Inside the events, I can not access the data via somthing like Eval("ID")
Currently we are using a very hacky solution:
string id = e.Item.FindControl("lblID").Text;
Where lblID is a hidden control that is populated with data in the aspx file using:
<asp:Label ID="lblID" runat="server" Text='<%# Eval("ID") %>' />
My eyes bleed when I look at this, Is there a better way?
In your event handlers, use the EventArgs object.
e.Item.DataItem
will give you the object you're looking for; you then just need to cast it to the type you need.
This MSDN page has a fuller example.
For the ItemCommand event handler, you may not have this option. In this case, I would use the CommandName and CommandArgument properties of the LinkButton (or whatever you're using). Put your ID as the CommandArgument, you can then pick this up from the event argument object in the event handler.
After a bit of tinkering I found the proper solution:
Data keys need to be added to the list view. Data keys are persistent unlike the data that is databound to a listview. To set the data key just specify the name in the ListView tag:
<asp:ListView ID="MyListview" runat="server" DataKeyNames="ID" ......
Then to access the keys from the event:
protected void MyListView_ItemCommand(object sender, ListViewItemEventArgs e)
{
// Get the item index of the Item
int itemIndex = ((ListViewDataItem)e.Item).DisplayIndex;
// Extract the key and cast it to its data type.
DataKey key = ((ListView)sender).DataKeys[itemIndex];
int myId = (int) key;
// Use ID to delete / modify the item in the SQL database....
}
Just to expand on the ItemDataBoundEvent solution you alluded to, you don't need to go via the ListView's DataKeys to access the data in the ItemDataBoundEvent. Casting e.Item to ListViewDataItem gives you access to the DataItem property which you can then cast to the underlying data type, giving you intellisense access to every underlying data field. Example:-
(ActualDataType)(((ListViewDataItem)e.Item).DataItem)

ASP.NET Convert Invalid String to Null

In my application I have TextBox in a FormView bound to a LinqDataSource like so:
<asp:TextBox ID="MyTextBox" runat="server"
Text='<%# Bind("MyValue") %>' AutoPostBack="True"
ontextchanged="MyTextBox_TextChanged" />
protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
MyFormView.UpdateItem(false);
}
This is inside an UpdatePanel so any change to the field is immediately persisted. Also, the value of MyValue is decimal?. This works fine unless I enter any string which cannot be converted to decimal into the field. In that case, the UpdateItem call throws:
LinqDataSourceValidationException -
Failed to set one or more properties on type MyType. asdf is not a valid value for Decimal.
I understand the problem, ASP.NET does not know how to convert from 'asdf' to decimal?. What I would like it to do is convert all these invalid values to null. What is the best way to do this?
I think you should handle the Updating event of the LinqDataSource on your page. Do your check for invalid strings (use a TryParse method or something) and then continue with the base class update.
(Edit: My intuition lines up with what's recommended here)
Not familiar with ASP, but in .net, couldn't you just do something along the lines of
protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
Decimal d = null;
TextBox tb = sender as TextBox;
if(!Decimal.TryParse(tb.Text, out d))
{
tb.Text = String.Empty;
}
MyFormView.UpdateItem(false);
}

Resources