I have a decimal data type in my model and an annotation to format it so it adds commas after 3 digits:
[DisplayFormat(DataFormatString = "{0:#,###0.00}" + " (USD)")]
public decimal PaidAmount { get; set; }
when I have any DisplayFor(m => m.PaidAmount) the formatting displays correctly (1,200.00 USD). However, in Ajax.ActionLink the first argument takes a string for the text to display so I can't use a lambda expression (m => m.PaidAmount). When I do:
Ajax.ActionLink(Model.PaidAmount.ToString(), //rest of link params)
the formatting doesn't apply to the link text, it shows just a bunch of numbers without commas (1200.00 USD, note there is no comma after the 1)
my guess is that using the capital 'M'odel version of model loses its annotation properties, is there a way to go around this and apply the formatting to the ajax.actionlink?
You can use
#Ajax.ActionLink(string.Format("{0:#,##0.00 USD}", Model.PaidAmount), ...)
Note I think you mean 0:#,##0.00 not 0:#,###0.00 (i.e. 10,200.00 USD, not 1,0200.00 USD)
Data annotations will not work in this case as they are checked in HtmlHelpers and won't affect regular ToString.
You can create an extension method to format your number an call it in your view:
public static class Extensions
{
public static string ToCurrency(this decimal number)
{
return number.ToString("{0:#,###0.00}") + " (USD)";
}
}
In you view: (don't forget to reference the Extensions class either directly in the view or in web.config under views folder)
Ajax.ActionLink(Model.PaidAmount.ToCurrency(), //rest of link params)
Related
I have a file with various characters and either words as well as numbers. These numbers can be integers like a 1 or 12 (as an example) or they have a comma and countless digits after the comma.
for example:
",{"n":"Box","p":[-4.0,4.0,0.0],"r":[270.0,0.0,0.0],"s":[1.0,1.000006,1.000006],"c":[0.448529363,0.4280135,0.412251264],"m":"wood_14"}"
The file is read with File.ReadAllText and then passed to NewtonsoftJson via JsonProperty accordingly
for example:
[JsonProperty("s")]
public double[] Scale
{
get;
set;
}
For example, with Scale, I want to limit the decimal places to a maximum of 5 digits.
Is this possible and if so, how?
I have been trying for days with different things, but nothing has worked yet.
My idea was to intervene in the string I build first before passing that to Json there. But unfortunately this does not work. I tried it with regular expression like Notepadd++ makes for example.
(edit)
I don't know if you want it to serialize or deserialize. So I made code for both cases. You have to leave one variant or another
public class a
{
private double[] val;
[JsonProperty("s")]
public double[] Scale
{
get { return val;
// or
val?.Select(v => Math.Round(v, 5)).ToArray(); }
set {
val=value;
//or
val = value?.Select(v => Math.Round(v, 5)).ToArray();
}
}
}
if you want it in many properties you can make it as a function
double.ToString() will do it.
const double d = 0.123456789;
string s = d.ToString("G5");
Console.WriteLine(s);
That outputs 0.12346, showing that it rounds the 5 to 6.
Documentation for Double.ToString shows much more detailed examples of how to format numbers.
The number format (i.e. decimal separator) is culture-specific. If you want to use the current culture, then the above will work. If you always want a comma as the decimal separator, you'll have to call the overload that accepts an IFormatProvider for the specific culture.
I have a DataGridViewTextBoxColumn which is binded to a property. I want to allow user to input numbers no matter what he uses to separate decimals. Also I don't need spaces or commas to separate thousads.
It's simple:
1.908 = 1.908
1,908 = 1.908
And if there is no way to specify format string, can i Replace(",",".") before binding? Or any other way?
Thank you. (Sorry for my English)
Crete another property of String type which will be bounded to that column.
Then set/read value of original property through this
public class YourBindableItem
{
public decimal OriginalValue { get; set; }
public decimal ParsedValue
{
get { return this.OriginalValue.ToString(); }
set
{
string forParse =
value.Replace(",", Globalization.CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator);
decimal temp = 0;
if(decimal.TryParse(forParse,
out temp,
Globalization.CultureInfo.InvariantCulture) == true)
{
this.OriginalValue = temp;
}
//if value wasn't parsed succesfully, original value will be returned
this.RaiseOnPropertyChanged(nameOf(this.ParsedValue));
}
}
}
The DataGridView already formats according to the regional settings for the current user, at least if you data bind to an object data source and the property is numeric (i.e. not a string).
You can test this by opening Region and Language in Windows and switching between e.g. the English (United States) format and Swedish (Sweden). In the former case, the input 2.718 will parse correctly while in the second 2,718 will. You'll have to run without debugging in VS in order to load fresh settings.
(I would not suggest trying to parse both comma and dot as a decimal separator for the same user, if you're thinking of doing that. That's not the expected behavior for most users and it would lead to bugs if the user should happen to use the thousand separator too.)
I am using the CsvHelper package to write my C# models to Csv. I am using fluent class maps (inheriting from CsvClassMap) to define my field to property mappings.
The issue I have is that some of the property values look like dates to excel. For example "2 - 4". I expect the end user to use excel to view these CSV's. I do not want these values to show as dates, so I am looking to have CsvHelper surround this field by quotes. However, I want ONLY this field surrounded by quotes. There are OTHER fields containing data I WANT to be interpreted (e.g. dates). Can I configure my mapping to specify this field should be quoted? I've played with using a type converter, but that's clearly the wrong approach because this is converting the VALUE and not instructing how to format the field.
As of version 12 you can do this:
const int indexToQuote = 4;
csv.Configuration.ShouldQuote = (field, context) =>
context.Record.Count == indexToQuote &&
context.HasHeaderBeenWritten;
So, apparently quoting is not what I needed to do. Excel quite helpfully decides to treat numeric values that look remotely like dates as dates, unless the field begins with a space (which it then will not display). I feel like relying on this is rather hackish, but I'll take it. FWIW, here's the type converter I used:
public class LeadingSpaceTypeConverter : DefaultTypeConverter {
public override string ConvertToString( TypeConverterOptions options, object value ) {
if (value == null ) {
return String.Empty;
}
return String.Concat(" ", value.ToString());
}
}
And the fluent code:
Map( m => m.CompanySize ).TypeConverter<LeadingSpaceTypeConverter>().Index( 4 );
I have looked through stackoverflow trying to find a solution to this but with no luck so hence why I have resulted in asking the question..
I have a field on my form which is price, type of decimal this is optional depending on what they have selected from a dropdown, So I cant use the [Required] attribute.
When the form is submitted if they have chosen a value from the dropdown which requires the user to enter a postage price I then need to check this field to make sure its a valid decimal so to do this I have the following
public static bool IsValid(decimal postagePrice)
{
var regex = new Regex(#"^\d+.\d{0,2}$");
return regex.IsMatch(postagePrice);
}
But it complains and says "Argument type decimal is not assignable to parameter type string" which I understand, I also can't use Decimal.TryParse as that expects a string.
How can I resolve this (I'm not in a position to change the type from decimal to string either)
If all you want is to verify that the value has at most two decimal positions, you could use a modulo:
public static bool IsValid(decimal postagePrice)
{
return postagePrice % 0.01m == 0m;
}
Regular expressions work on strings - it's that simple.
So in one way or another you'll need to covert the decimal to a string before using a regex to validate it.
I have a problem with decimal numbers.
If I use .(dot) instead of ,(comma) in the textbox it comes null in controller.
I know its a language issue because in spanish we use comma instead of dot for decimals but I need to use dot.
It is possible to change this?
It is strange because in controller I have to use .(dot) for decimals i.e:
I can do float x = 3.14 but I can not do float x = 3,14 so I do not understand this... In some cases I have to use dot... In others I have to use comma...
This is my code:
In model:
[Display(Name = "Total")]
public double Total { get; set; }
In view:
#Html.EditorFor(model => model.Total, new { id = "Total", htmlAttributes = new {#class = "form-control" } })
In controller:
public ActionResult Create([Bind(Include = "ID,Codigo,Fecha,Trabajo,Notas,BaseImponible,Iva,Total,Verificado,FormaDePagoID,ClienteID")] Presupuesto presupuesto)
{
Thanks everybody. I found this code from Phil Haack that works pretty well.
Create a class in any folder of your project
public class ModelBinder
{
public class DecimalModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
object result = null;
// Don't do this here!
// It might do bindingContext.ModelState.AddModelError
// and there is no RemoveModelError!
//
// result = base.BindModel(controllerContext, bindingContext);
string modelName = bindingContext.ModelName;
string attemptedValue =
bindingContext.ValueProvider.GetValue(modelName).AttemptedValue;
// Depending on CultureInfo, the NumberDecimalSeparator can be "," or "."
// Both "." and "," should be accepted, but aren't.
string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
string alternateSeperator = (wantedSeperator == "," ? "." : ",");
if (attemptedValue.IndexOf(wantedSeperator) == -1
&& attemptedValue.IndexOf(alternateSeperator) != -1)
{
attemptedValue =
attemptedValue.Replace(alternateSeperator, wantedSeperator);
}
try
{
if (bindingContext.ModelMetadata.IsNullableValueType
&& string.IsNullOrWhiteSpace(attemptedValue))
{
return null;
}
result = decimal.Parse(attemptedValue, NumberStyles.Any);
}
catch (FormatException e)
{
bindingContext.ModelState.AddModelError(modelName, e);
}
return result;
}
}
}
Add this to Application_Start() method in Global.asax
ModelBinders.Binders.Add(typeof(decimal), new ModelBinder.DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new ModelBinder.DecimalModelBinder());
Now use decimal type instead of float or double and everything will go fine !!
Thank you mates see you around !.
Your controller uses C#. The language specific states that . is the decimal separator. Period. It's not language specific, that's just it.
Your database or UI (which uses the server's language settings) might use another decimal separator than the default (US) language setting C# uses. That's why you have to use , as separator there.
you would need to use a custom model binder.
See this blog post http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/
If you want your comma(,) separated decimal input in UI as per UI culture, to be converted to dot(.) to bind to C# decimal number, you can go for Asp.Net MVC's custom model binder, where take the comma separated decimal string and replace the comma with a dot and then assign to the C# decimal property.
The advantage is, its reusable across the application, where you might be having recurring scenarios for decimal conversions.
Hope following links could help you:
ASP.Net MVC Custom Model Binding explanation
http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx
http://haacked.com/archive/2011/03/19/fixing-binding-to-decimals.aspx/