Converting an integer to a string, through an object - c#

I'm pretty new to XAML and WPF, and I'm trying to build a Converter, which converts an integer to a month (string)
I know the code below doesn't work because it gets an object rather than a string to process, but I have no idea how to handle this object?
public class NumberToMonthConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value is int)
{
string strMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(value);
return strMonthName;
}
}
}

You are pretty close, just cast value to int after you checked it is an int:
if (value is int)
{
return CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName((int)value);
}
else // you need this since you need to return a value
{ // throw an exception if the value is unexpected
throw new ArgumentException("value is not an int", "value");
}

why dont use TryParse?
int i;
if (int.TryParse(value, out i)) {
string strMonthName = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(i);
return strMonthName;
}
else {
throw new Exception("value is not int!");
--OR--
return "Jan"; //For example
}

Related

How to override exception message generated by IValueConverter

I would like to override message provided by the custom conversion class which inherits IValueConverter interface.
public class BoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//string convertedValue = "";
bool initialValue = (bool)value;
if (initialValue == false)
{
return "0";
}
else if (initialValue == true)
{
return "1";
}
else return null;//{ return convertedValue; }
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string initialValue = ((string)value).Trim();
try {
if (initialValue == "1") { return true; }
else if (initialValue == "0") { return false; }
else { return null; }
}
catch (Exception)
{
return null;
}
}
}
For example, if I enter 3 into text box binded with property I am receiving message: Value '3' could not be converted. I would like to provide longer message.

Converting decimal number c#

This may be something similar to other but my understanding is not great so I'm trying to see if anyone can help me understand. I want to change the decimal place of a number, for example if the number is 0.5 I want it to convert it to .50, likewise if it was 0.25 then .25, etc, I'm guessing this is so simple but I can't seem to understand how to do this? My unit test code I have is below and the first one passes but not the others
Updated Unit Test
[TestFixture]
public class ProbabilityDisplayConverterTests
{
public ProbabilityDisplayConverter underTest = new ProbabilityDisplayConverter();
[Test]
public void Convert_ConvertsWholeDecimal()
{
var value = (string)underTest.Convert(1, typeof(decimal), null, CultureInfo.CurrentCulture);
Assert.AreEqual("1", value);
}
[Test]
public void Convert_ConvertsHalfToDecimal()
{
var value = (string)underTest.Convert(0.5, typeof(decimal), null, CultureInfo.CurrentCulture);
Assert.AreEqual(".50", value);
}
[Test]
public void Convert_ConvertsDecimal()
{
var value = (string)underTest.Convert(0.25, typeof(decimal), null, CultureInfo.CurrentCulture);
Assert.AreEqual(".25", value);
}
[Test]
public void Convert_ConvertsWholeNumberDecimal()
{
var value = (string)underTest.Convert(0.3, typeof(decimal), null, CultureInfo.CurrentCulture);
Assert.AreEqual(".30", value);
}
}
EDIT
public class ProbabilityDisplayConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value = value.ToString("G", CultureInfo.InvariantCulture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I´m not sure if I miss something in this question, but why not simply use the format option of the ToString method?
(0.5m).ToString(".00");
(0.15m).ToString(".00");
does exactly what the OP Need (of course you get your local decimal point char)
Try this
number = .0023;
Console.WriteLine(number.ToString("G", CultureInfo.InvariantCulture));
reference: https://msdn.microsoft.com/ru-ru/library/dwhawy9k(v=vs.110).aspx

How to convert an arbitrary object to enum?

I have an object. Usually it is either long or string, so to simplify the code let's assume just that.
I have to create a method that tries to convert this object to a provided enum. So:
public object ToEnum(Type enumType, object value)
{
if(enumType.IsEnum)
{
if(Enum.IsDefined(enumType, value))
{
var val = Enum.Parse(enumType, (string)value);
return val;
}
}
return null;
}
With strings it works well. With numbers it causes problems, because a default underlying type for enum is int, not long and IsDefined throws an ArgumentException.
Of course I can do many checks, conversions or try-catches.
What I want is to have a clean and small code for that.
Any ideas how to make it readable and simple?
It feels to me like you only actually want to handle three cases:
Input is already the right type
Strings
Integers in various types
I believe this will do what you want for valid input:
public object ToEnum(Type enumType, object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (enumType == null)
{
throw new ArgumentNullException("type");
}
if (!enumType.IsEnum)
{
return false;
}
string valueString = value as string;
if (valueString != null)
{
return Enum.IsDefined(enumType, value) ? Enum.Parse(enumType, valueString) : null;
}
if (value.GetType() == enumType)
{
return value;
}
// This appears to handle longs etc
return Enum.ToObject(enumType, value);
}
However, that will return a value of the right type even for undefined values. If you don't want that, change the last part to:
object candidate = Enum.ToObject(enumType, value);
return Enum.IsDefined(enumType, candidate) ? candidate : null;
Also, this will still throw an exception if you pass in a floating point number, or something like that. If you don't want that behaviour, you'll need to have a set of all the types you do want to accept, and check against that first.
Try this
public object ToEnum<T>(object value)
{
var type = typeof(T);
if (type.IsEnum)
{
int numberVal;
if (!int.TryParse(value.ToString(), out numberVal) && value.GetType() != typeof(string))
{
return null;
}
value = numberVal;
if (Enum.IsDefined(type, value))
{
T result = (T)Enum.Parse(type, value.ToString());
return result;
}
}
return null;
}

Error validation with IDataErrorInfo and IValueConverter

I have a class with a List<string> Tags that I want to display in a TextBox. For this I use a IValueConverter.
ListToStringConverter:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var list = value as List<string>;
var returnvalue = string.Empty;
if(list != null)
list.ForEach(item => returnvalue += item + ", ");
return returnvalue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var strValue = value as string;
if(strValue != null)
return strValue.Split(new char[] { ',' });
return null;
}
Class Test:
public class Test : IDataErrorInfo
{
public Test()
{
Tags = new List<string>();
}
public List<string> Tags { get; set; }
string errors;
const string errorsText = "Error in Test class.";
public string Error
{
get { return errors; }
}
public string this[string propertyName]
{
get
{
errors = null;
switch (propertyName)
{
case "Tags":
if (Tags.Count <= 1)
{
errors = errorsText;
return "...more tags plz..";
}
break;
}
return null;
}
}
}
Now I want to Validate the Tags:
<TextBox Text="{Binding Test.Tags, Converter={StaticResource ListToStringConverter}, Mode=TwoWay, ValidatesOnDataErrors=True}" />
But there is no error displayed. Maybe because of the conversion but how can i still accomplish a validation?
I don't see why it shouldn't work. If you will run this at first time - SL will highlight the TextBox with red border. But if you will try to change the list of tags - you will see nothing, because you in your converter you have a bug in ConvertBack you return type array of strings (string[]), but property expects object with type List, so you just need to update the ConvertBack method to:
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var strValue = value as string;
if (strValue != null)
return strValue.Split(new char[] { ',' }).ToList();
return null;
}
One more note about Convert method, you can use Join method:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var list = value as List<string>;
if (list != null)
return String.Join(", ", list);
return null;
}
And one more thing about combining the strings. Don't use operator +, because you can have performance issues with it, use StringBuilder instead.

workflow 4 activity designer IValueConverter

Lets say i have an activity with InArgument<int> ProductId
I'd like to expose in the activity designer a combobox to show all Products and the user can select a product.
I can show the list of product in the combo no problem. But how do I bind the selected product to the InArgument<int> of my custom activity?
I suppose I need some kind of ValueConverter? Not sure how to code the value converter for this case, if anybody has an idea, suggestion, will be helpful. I have to convert the InArgument<int> to an int? and the convert back from int to InArgument<int>
Thanks,
public class ArgumentToInt32Converter: IValueConverter {
object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
object convertedValue = null;
if (value != null) {
ModelItem argumentModelItem = value as ModelItem;
if (argumentModelItem != null && argumentModelItem.Properties["Expression"] != null && argumentModelItem.Properties["Expression"].Value != null) {
if (argumentModelItem.Properties["Expression"].ComputedValue.GetType() == typeof(Literal <Int32> )) {
convertedValue = (argumentModelItem.Properties["Expression"].ComputedValue as Literal <Int32> ).Value;
} else {
convertedValue = null
}
}
}
return convertedValue;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
// Convert Int32 value to InArgument<Int32>
Int32 itemContent = (Int32) value;
VisualBasicValue <Int32> vbArgument = new VisualBasicValue <Int32> (itemContent);
InArgument <Int32> inArgument = new InArgument <Int32> (vbArgument);
return inArgument;
}
}
Modified from this answer
This is my attempt at making a more generic solution to this. I have several properties - some IEnumerable, some string, some int, and to make a value converter for each seems like the wrong approach. I'd be interested to know what cases I haven't caught here because I am relatively new to WF. Hopefully this helps someone.
public class ArgumentConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
object convertedValue = null;
if(value != null)
{
var argumentModelItem = value as ModelItem;
if(argumentModelItem != null)
{
ModelProperty argumentModelProperty = argumentModelItem.Properties["Expression"];
if(argumentModelProperty != null && argumentModelProperty.Value != null)
{
var computedValue = argumentModelProperty.ComputedValue;
var activity = (Activity) computedValue;
convertedValue = WorkflowInvoker.Invoke(activity)["Result"];
}
}
}
return convertedValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// here targetType should be InArgument<T>
// assume a single generic argument
Type arg0 = targetType.GetGenericArguments()[0];
ConstructorInfo argConstructor = targetType.GetConstructor(new[] {arg0});
var argument = argConstructor.Invoke(new[] { value });
return argument;
}
#endregion
}

Categories