Parsing Decimals from a String - c#

I have a dropdownlist on a web form that has an item name and a price associated with it (which is not visible to the user). I am using selecteditem.Text and selectedvalue to capture the item name and the price. To combat duplicate entries for the selectedvalue I am storing entries like so
Signed Cap 10.0
Signed Glove 10.1
Signed Shirt 10.2
Bat Shavings .50
Hat Brim .50
Then parsing it out by using the below
String[] str = dropdownlist1.SelectedValue.ToString().Split('.');
String itemprice = str[0].Trim();
My syntax works great, EXCEPT for the decimal values! On Bat Shavings and Hat Brim I need to retain the decimal value! What should I alter or how should I set up my syntax to allow duplicate selected values or to keep the decimals? I understand that using str[0] is what is causing me to loose the decimals, BUT how can I work around it for the 2 (possibly more in the future) scenarios where they need to be remain in tact?

Its hard to tell from your posting how your getting your data, but I would load my data from the database into a data object, then bind that object to the drop down list.
Here is the Inventory Class I used to store the data from the database:
public class Inventory
{
public int ProductID { get; set; }
public string ProductDescription { get; set; }
public decimal ProductPrice { get; set; }
public Inventory(int ID, string Description, decimal Price)
{
this.ProductID = ID;
this.ProductDescription = Description;
this.ProductPrice = Price;
}
public string DDLValue
{
get
{
return string.Format("{0}|{1}|{2}", ProductID, ProductDescription, ProductPrice);
}
}
public string DDLText
{
get
{
return string.Format("{0} [{1}]", ProductDescription, ProductPrice.ToString("C"));
}
}
}
Here is a sample of how to configure the page control:
<asp:DropDownList ID="ddlProducts" runat="server" DataValueField="DDLValue" DataTextField="DDLText" />
In the page code behind, load your data into the drop down:
protected void LoadProductsFromDatabase()
{
System.Collections.Generic.List<Inventory> My_DDL_Datasource = new System.Collections.Generic.List<Inventory>();
// write your code to pull database values
// populating list with sample data for stackoverflow
// make sure to use a replace statement to remove any delimiter characters that may be in the description
My_DDL_Datasource.Add(new Inventory(1, "Product 1".Replace("|", ""), 0.50m));
My_DDL_Datasource.Add(new Inventory(2, "Product 2".Replace("|", ""), 1.50m));
My_DDL_Datasource.Add(new Inventory(3, "Product 3".Replace("|", ""), 0.50m));
My_DDL_Datasource.Add(new Inventory(4, "Product 4".Replace("|", ""), 10.50m));
ddlProducts.DataSource = My_DDL_Datasource;
ddlProducts.DataBind();
}
In the page code behind, create a method to get your drop down list selected value:
protected Inventory GetSelectedProduct()
{
try
{
if (ddlProducts.Items.Count == 0)
{
// do nothing, fall thru will return null
}
else
{
string[] DDLValue = ddlProducts.SelectedValue.Split('|');
int ivalue = 0;
int.TryParse(DDLValue.GetValue(0).ToString(), out ivalue);
decimal dvalue = 0.00m;
decimal.TryParse(DDLValue.GetValue(2).ToString(), out dvalue);
// only return object if the productid and product price were successfully parsed.
// this logic assumes no products are free
if (ivalue > 0 && dvalue > 0.00m)
{
return new Inventory(ivalue, DDLValue.GetValue(1).ToString(), dvalue);
}
}
}
catch { }
return null;
}
In the page code behind, do something with your selected value:
protected void DoSomethingWithValue()
{
Inventory MyInventoryItem = GetSelectedProduct();
if (MyInventoryItem != null)
{
// selected item successfully parsed
// do something with it.
Response.Write(
string.Format("Your selected product:<br />{0}<br />UniqueID: {1}<br />Price: {2}",
Server.HtmlEncode(MyInventoryItem.ProductDescription),
MyInventoryItem.ProductID,
MyInventoryItem.ProductPrice.ToString("C")
));
}
else
{
// error parsing information stored in drop down list value
}
}

You can split on space, and always take the last entry using linq:
dropdownlist1.SelectedValue.ToString().Split(' ').Last();
Note you should be using a hidden ItemId as the selectedvalue, instead of item name and price, and use a lookup table of:
ItemId|Name|Price
1|Hat|.50
2|Bat Shavings|.50
...
When the selected id is submitted you can lookup the name and price more directly. Also, the price being hidden in a form doesn't prevent the user from manipulating the price.

You need to remove/replace all alpha characters from string and keep only numeric.
Regex rgx = new Regex("[^a-zA-Z]");
str = rgx.Replace(str, "").Trim();
decimal prc;
Decimal.TryParse(str, out prc);

Related

Even same strings does not match

Hello i have a datagridview which has datasource of list and this list is:
public class UniqueNounWithFreq
{
public int freq { get; set; }
public string word { get; set; }
public UniqueNounWithFreq(string word, int freq)
{
this.freq = freq;
this.word = word;
}
}
if (e.KeyChar == (char)13)
{
foreach (DataGridViewRow item in dataGridView_w2wm2.Rows)
{
if (!item.Cells[2].Value.ToString().Contains(textBox1.ToString().ToLower()))
{
item.Visible = false;
}
else
{
item.Visible = true;
}
}
}
When I want to hide a row with key press it throws
Row associated with the currency manager's position cannot be made invisible exception
Which you can see here : Unable To set row visible false of a datagridview. I tried the method sugested there but it did not work for me. Also when I check the lengths of the strings I wrote even if they are same they does not match. if you can help me I appreciate that.
Using textBox1.ToString() will generate something like "System.Windows.Controls.TextBox: TextBox" - it will create a string of the control type.
You should be using textBox1.Text to get the actual contents of the textbox - it is a string, so does not need converting.
Following on from PeterBruins comment using .Contains(textBox1.Text, StringComparer.CurrentCultureIgnoreCase) would be better than converting to lower case.
You could simplify setting the Visible property without use of an if statement to :
item.Visible = item.Cells[2].Value.ToString().Contains(textBox1.Text,
StringComparer.CurrentCultureIgnoreCase);

Loop through Request.Forms to get Field Values for Bulk Update

I have a list of records generated from a search query in my View. There's certain fields that can be edited and next step is do update those fields with one button/action.
The yellow fields are the ones that have been edited, while the white fields still match what is in the database table. Now when I click update all I first get the values of sellprice and casecost from the DB, then I get the values from the form. If the values match then move on, if the values from the form have been changed then update. I have datareader that reads the values from the table/database perfectly fine for each line of records on page.
NpgsqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
var prod = new ProductViewModel();
prod.q_guid = Guid.Parse(dr["q_guid"].ToString());
prod.q_sellprice = Convert.ToDecimal(dr["q_sellprice"]);
prod.q_casecost = Convert.ToDecimal(dr["q_casecost"]);
/*
At this point
Need to compare dr.Read q_sellprice and q_casecost
with changed values in the fields
if != then update for that record
*/
/*Lets assign previous values (values in db) to variables*/
var previousSellprice = prod.q_sellprice;
var previousCasecost = prod.q_casecost;
var thatId = prod.q_guid;
/*Lets get current values from form/list*/
var priceList = Request.Form["item.q_sellprice"];
var costList = Request.Form["item.q_casecost"];
/*eg*/
if (previousSellprice != currentSellprice || previousCasecost != currentCasecost)
{
//lets update record with new values from view
}
-> loop move on to next row in view
My DataReader while loop can get the value of each row no problemo. What I am trying to achieve when it gets the values of the first row from the db, then
I need to check what the current values in the form for that record are
if they are different then update for that current row
move on to next row in the view/on page
I have managed to get the array of values for these fields with these variables with the following code. This has the edited/changed fields from the list/form.
var priceList = Request.Form["item.q_sellprice"];
var costList = Request.Form["item.q_casecost"];
On my first run through the loop, I would like to get the values 10.00 and 8.50, do my check, update if necessary.. then move on the next row which will get 3.33 and 8.88, do my check, and update if necessary and so on for the rest of the records on that page.
So how can I loop through Request.Forms in the instance, and get my individual values for one record at a time?
cshtml on view for the fields is
#foreach (var item in Model)
{
<td>
€ #Html.EditorFor(modelItem => item.q_sellprice, new { name="q_sellprice" })
</td>
<td>
€ #Html.EditorFor(modelItem => item.q_casecost, new { name="q_casecost"})
</td>
Addition: Updating isnt the issue, getting the values of each record from the array while looping through the form fields is.
It is a long description of the problem - but from my understanding, your only problem is, that you want to have some data, which right now is two strings to be as List of operations (data) to perform? Is that correct?
If so - you can have such data in List using Zip method:
void Main()
{
string priceList = "1,2,3,4";
string costList = "2,3,4,5";
var prices = priceList.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries);
var costs = costList.Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries);
var collectionToUpdate = prices.Zip(costs, (price, cost) => new PriceToUpdate(price, cost));
//do update in database with collectionToUpdate
}
public class PriceToUpdate
{
public PriceToUpdate(string oldPrice, string newPrice)
{
decimal priceTmp;
if (decimal.TryParse(oldPrice, out priceTmp))
{
OldPrice = priceTmp;
}
if (decimal.TryParse(newPrice, out priceTmp))
{
NewPrice = priceTmp;
}
}
public decimal OldPrice { get; set; }
public decimal NewPrice { get; set; }
}
My suggestion would be to re-organise your HTML a bit more and modify the method for getting the fields parsed out. What I have done in the past is include the Key Id (in your case the Guid) as part of the output. So the result in a basic view looks like:
If you notice the name attribute (and Id) are prefixed with the q_guid field. Here is my basic model.
public class ProductViewModelItems
{
public IList<ProductViewModel> items { get; set; } = new List<ProductViewModel>();
}
public class ProductViewModel
{
public Guid q_guid { get; set; }
public decimal q_sellprice { get; set; }
public decimal q_casecost { get; set; }
//other properties
}
And my controller just has a simple static model. Of course yours is built from your database.
static ProductViewModelItems viewModel = new ProductViewModelItems()
{
items = new[]
{
new ProductViewModel { q_casecost = 8.50M, q_sellprice = 10M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 8.88M, q_sellprice = 3.33M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 9.60M, q_sellprice = 3.00M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 9.00M, q_sellprice = 5.00M, q_guid = Guid.NewGuid() },
new ProductViewModel { q_casecost = 10M, q_sellprice = 2.99M, q_guid = Guid.NewGuid() },
}
};
[HttpGet]
public ActionResult Index()
{
//load your view model from database (note mine is just static)
return View(viewModel);
}
Now we construct our form so that we can pull it back in our post method. So I have chosen the format of {q_guid}_{field_name} as
q_casecost = {q_guid}_q_casecost
q_sellprice = {q_guid}_q_sellprice
The form construction now looks like.
#foreach (var item in Model.items)
{
<tr>
<td>
€ #Html.TextBoxFor(modelItem => item.q_sellprice, new { Name = string.Format("{0}_q_sellprice", item.q_guid), id = string.Format("{0}_q_sellprice", item.q_guid) })
</td>
<td>
€ #Html.TextBoxFor(modelItem => item.q_casecost, new { Name = string.Format("{0}_q_casecost", item.q_guid), id = string.Format("{0}_q_casecost", item.q_guid) })
</td>
</tr>
}
Note there a few key items here. First off you cant modify the Name attribute using EditorFor() so I have swapped this out to a TextBoxFor() method.
Next I am overriding the Name attribute (note it must be Name not name [lower case ignored]).
Finally the POST action runs much differently.
[HttpPost]
public ActionResult Index(FormCollection form)
{
IList<ProductViewModel> updateItems = new List<ProductViewModel>();
// form key formats
// q_casecost = {q_guid}_q_casecost
// q_sellprice = {q_guid}_q_sellprice
//load your view model from database (note mine is just static)
foreach(var item in viewModel.items)
{
var caseCostStr = form.Get(string.Format("{0}_q_casecost", item.q_guid)) ?? "";
var sellPriceStr = form.Get(string.Format("{0}_q_sellprice", item.q_guid)) ?? "";
decimal caseCost = decimal.Zero,
sellPrice = decimal.Zero;
bool hasChanges = false;
if (decimal.TryParse(caseCostStr, out caseCost) && caseCost != item.q_casecost)
{
item.q_casecost = caseCost;
hasChanges = true;
}
if(decimal.TryParse(sellPriceStr, out sellPrice) && sellPrice != item.q_sellprice)
{
item.q_sellprice = sellPrice;
hasChanges = true;
}
if (hasChanges)
updateItems.Add(item);
}
//now updateItems contains only the items that have changes.
return View();
}
So there is alot going on in here but if we break it down its quite simple. First off the Action is accepting a FormCollection object which is the raw form as a NameValuePairCollection which will contain all the keys\values of the form.
public ActionResult Index(FormCollection form)
The next step is to load your view model from your database as you have done before. The order you are loading is not important as we will interate it again. (Note i am just using the static one as before).
Then we iterate over each item in the viewmodel you loaded and now are parsing the form values out of the FormCollection.
var caseCostStr = form.Get(string.Format("{0}_q_casecost", item.q_guid)) ?? "";
var sellPriceStr = form.Get(string.Format("{0}_q_sellprice", item.q_guid)) ?? "";
This will capture the value from the form based on the q_guid again looking back at the formats we used before.
Next you parse the string values to a decimal and compare them to the original values. If either value (q_sellprice or q_casecost) are different we flag as changed and add them to the updateItems collection.
Finally our updateItems variable now contains all the elements that have a change and you can commit those back to your database.
I hope this helps.

c# int value not selected correctly with linq query

I've build a database using Entity Framework Code First.
I was trying to do a simple LINQ query ad display data of a table in a listbox, but an int value always results as 0.
So I tried to do a debug and in XAML.CS at this point:
var item = (from Item in db.Items
select Item ).ToList();
My "Price" value is 0 when the entity is selected, but it should be 7
EDIT
Item.cs
public int Price
{
get { return price; }
set { price = value / 100; }
}
set { price = value / 100; }
There's your problem... I don't know what that's supposed to do, but remove the / 100 and it'll work.
7 / 100 is 0, since you're doing integer division.
If you want to show prices with decimal fractions, make the property and column a decimal.
Alternatively, if you're stuck with the int column for some reason, see How to map column and entity propery of different datatypes in entity framework code first how to do that:
// An int property to map to your database:
[Column("Price")]
public int PriceInt { get; set; }
// Use this property from code.
[NotMapped]
public decimal Price
{
// Cast to decimal for decimal division.
get { return (decimal)PriceInt / 100; }
set { PriceInt = (int)(value * 100); }
}

The best overloaded method match for... has some invalid arguments

I am using DataAdapter("SDM_Tran_GenerateInvoice") inside DataSet("SDMDAL.xsd") in my project.
Below is the structure of DataAdapter along with the Stored Procedure names in it:
Below is the Table structure Im using for the same:
I am calling this DataAdapter inside Class file named as SDM.InvoiceBLL.cs:
using SDMDALTableAdapters;
public class SDM_Invoice
{
private SDM_Tran_GenerateInvoiceTableAdapter _GenerateInvoiceTableAdapter = null;
protected SDM_Tran_GenerateInvoiceTableAdapter Adapter
{
get
{
if (_GenerateInvoiceTableAdapter == null)
_GenerateInvoiceTableAdapter = new SDM_Tran_GenerateInvoiceTableAdapter();
return _GenerateInvoiceTableAdapter;
}
}
#region GET
//to show data in Invoice Grid
public SDMDAL.SDM_Tran_GenerateInvoiceDataTable SelectInvoice(string _SPID)
{
return Adapter.SelectInvoice(_SPID);
}
//to show data in 1st hidden Grid
public SDMDAL.SDM_Tran_GenerateInvoiceDataTable GetInvoiceBillingBySPID(string _SPID)
{
return Adapter.GetInvoiceBillingBySPID(_SPID);
}
//to fetch InvoiceID for unique key generation
public SDMDAL.SDM_Tran_GenerateInvoiceDataTable GetInvoiceID()
{
return Adapter.GetInvoiceID();
}
//to fetch InvoiceNumber for unique key generation
public SDMDAL.SDM_Tran_GenerateInvoiceDataTable GetInvoiceNumber()
{
return Adapter.GetInvoiceNumber();
}
#endregion
public string Insert(string InvoiceID, string SPfoID, string InvoiceLineNo, string InvoiceNo, string InvoiceType, string BillingIDfoID, string BusinessUnit, string DirectCost, string InvfoStatusID, string Status, DateTime Date, string AccountCode)
{
string query = Convert.ToString(Adapter.Insert1(InvoiceNo, SPfoID, InvoiceLineNo, InvoiceNo, InvoiceType, BillingIDfoID, BusinessUnit, DirectCost, InvfoStatusID, Status, Date, AccountCode));
return query;
}
public SDM_Invoice()
{
}
}
and then calling the "Insert" function of class file inside Default.aspx.cs page, to save records on button click:
protected void btnInvoice_Click(object sender, EventArgs e)
{
generateInvoiceId();
generateInvoiceNumber();
string InvType = rlbInvType.SelectedValue;
string Status = "Draft";
string BillingID;
string DirectCost;
string BusinessUnit;
string StatusID;
string AccCode;
foreach (GridDataItem itm in rgData.Items)
{
BillingID = itm["BillingID"].Text;
DirectCost = itm["DCIDescription"].Text;
BusinessUnit = itm["BUName"].Text;
StatusID = itm["BUfoStatusID"].Text;
Label lb = (Label)itm.FindControl("Label1");
string InvLineNo = lb.Text;
try
{
SDM.Invoice.Insert(lblInvId.Text, _SPID, InvLineNo, lblInvNo, InvType, BillingID, BusinessUnit, DirectCost, StatusID, Status, DateTime.Now, AccCode);
}
catch (Exception ex)
{
}
}
}
I rebuilt my project number of times and when I run my web page "Default.aspx.cs", always it gives me below error:
The best overloaded method match for 'SDM_Invoice.Insert(string, string, string, string, string, string, string, string, string, string, System.DateTime, string)' has some invalid arguments
I searched many articles related to my issue but couldn't find any solution for my problem.
This is the first time I am working with TableAdapter. Please help me what is wrong in my code ? What am I missing in it. Thanks in advance.
All the arguments except for the next to last need to be strings, but you seem to be passing some non-string values, for example lblInvNo, which seems to be a user interface element.
Check the type of each argument aside from the next to last, and make sure they are all strings.

loop through database item, sum values and parse unwanted text

I am wondering about for each loop. What I have is several columns for each item and I want to loop trough it and take out values from each column that has the name "inch".
Now to the part where the value is not just numbers but also letters, like "1 inch".
So I have 3 items that has "1 inch","5 inch" and "10 inch".
So I want to take the "inch" (parse I guess) out and add these three together so the sum is 16.
This if for windows phone local database c#
I have a ViewModel and a Model. The columns in the Model looks like this
private string _itemSpring;
[Column]
public string ItemSpring
{
get { return _itemSpring; }
set
{
if (_itemSpring != value)
{
NotifyPropertyChanging("ItemSpring");
_itemSpring = value;
NotifyPropertyChanged("ItemSpring");
}
}
}
Then i view it through my viewmodel with connection string to db,
// LINQ to SQL data context for the local database.
public ToDoDataContext toDoDB;
// Class constructor, create the data context object.
public ToDoViewModel(string toDoDBConnectionString)
{
toDoDB = new ToDoDataContext(toDoDBConnectionString);
}
If your 3 items are like this,
string[] items = { "1 inch", "5 inch", "10 inch" };
int totalCount = 0;
foreach(var item in items)
{
string[] substrings = item.split(' ');
totalCount += int.Parse(substrings[0]);
}
string finalString = totalCount + " inch";
UPDATE:
I dont understand whether you are asking on how to retrieve the data from database or how to process the data that is fetched from DB.
Assuming the second case, check the following answer
Fetch the data from database and convert it into a List or an ObservableCollection
and then you can use the following query on that to get what you want.
foreach(var item in ItemsList)
totalCount += double.Parse(item.ItemSize.Split(' ')[0]);
or otherwise
foreach(var item in ItemsList)
totalCount += double.Parse(item.ItemSize.Replace(" inch", ""));

Categories

Resources