ASP.NET Convert Invalid String to Null - asp.net

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);
}

Related

changing textbox value in code behind does not post back new value

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
}

Data Bind Asp .Net Drop Down List SelectedValue to Page Property

I have a property in my Page
Public Property Status as String
I set up the status list manually by calling
list.Items.Add(New ListItem("Open", "Open"))
and then I call
list.DataBind()
On my page I want to set the selected value to the value in that property and I want the value in that property to contain the value of the list on each post back.
I tried SelectedValue='<%# Bind("Status") %>' but I get the following error:
Databinding methods such as Eval(), XPath(), and Bind() can only be
used in the context of a data bound control.
Is there something I am missing? The end goal is to have the state of the DropDownList persisted to the Page property between post backs.
Thank you.
You can get the selected value of dropdownlist by
status=DropDownList1.SelectedItem.Value.ToString();
In order to get selected value after each postback,you need to add event in your dropdownlist onselectedindexchanged="DropDownList1_SelectedIndexChanged" and in that event you can get selected value as follows.
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
status=DropDownList1.SelectedItem.Value.ToString();
}
you can persist the value of your status property by creating a view state as follows(in c#)
public string status
{
get
{
if (ViewState["status"] != null)
return ViewState["status"].ToString();
else
return null;
}
set
{
ViewState["status"] = value;
}
}
The server control has viewstate that persist the value of the control between postbacks automatically as long as you don't set the viewstate property of a control to false.
Second thing is you dont need to call it the DataBind() function in your case.

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)

How do I get the TotalRowCount from a LinqDataSource into a Literal?

I have a LinqDataSource that I use to calculate the number of rows in a table. I would like to update the value of literal with the number, with the following code, taken from MSDN (linqdatasourcestatuseventargs.totalrowcount.aspx):
protected void linqDataSource1_Selected(object sender, LinqDataSourceStatusEventArgs e)
{
Literal1.Text = e.TotalRowCount.ToString();
}
By how do I trigger the select event on the data source? The SqlDataSource class has a Select() method so that it can be triggered programmatically in e.g. Page_Load, but the LinqDataSource does not have this method. I currently solved the problem by binding my data source to an empty FormView element, but this is just too ugly.
I feel pretty confident that there is a much nicer way to get the total number of rows into my literal when using LinqToSql, I just don't know how to do so.
The suggestion by tvanfosson, of attaching an method to the data source's selected event, does unfortunately not solve my problem, because the select event is still not triggered when the page loads. (I have, by the way, already attached the _Selected method with the OnSelected attribute, like this)
<asp:LinqDataSource ID="linqDataSource1" runat="server"
OnSelected="linqDataSource1_Selected">
Hook up your method as an event handler for the Selected event in Page_Load.
public void Page_Load( object sender, EventArgs e )
{
linqDataSource1.Selected += LinqDataSource1_Selected;
}
protected void LinqDataSource1_Selected(object sender, LinqDataSourceStatusEventArgs e)
{
Literal1.Text = e.TotalRowCount.ToString();
}
I ended up dropping the data source and instead put the code in the code behind. Not really the point-and-click-programming that I was going for, but still quite short. I looks something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
var context = new MyDataContext();
numberOfModificationsLiteral.Text =
(
from modification in context.Modifications
where modification.Start >= DateTime.Now
select modification
).Count().ToString();
}
}

Resources