While developing a MultiValueConverter I ran into an odd error.
I am getting an 'Invalid Cast Exception' on the line:
int frameSize = (int)values[0] ; // <-- thows InvalidCast Exception
I honestly cannot determine why.
public class SizeConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length <3 || values[2] == null || values[1] == null || values[0] == null)
return 0;
int numItems = (int)values[2];
int separatorSize = (int)values[1];
int frameSize = (int)values[0] ; // <-- thows InvalidCast Exception
int totalSeparatorSize = (numItems - 1) * separatorSize;
int remainingArea = frameSize - totalSeparatorSize;
return remainingArea / numItems;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I verified the received values[3] array in the Converter in immediate Window:
`{object[3]}
[0]: 100
[1]: 2
[2]: 4`
Here is the calling code MSTest [TestClass]:
[TestClass]
public class TestConverters
{
[DataRow(100, 2, 4)]
[DataTestMethod]
public void Test_Piece_Sizing(double frameSize, int separatorSize, int numItems)
{
var sizeConverter = new SizeConverter();
object[] values = new object[] { frameSize, separatorSize, numItems };
Assert.AreNotEqual(0,sizeConverter.Convert(values, typeof(int), null, System.Globalization.CultureInfo.CurrentCulture));
}
}
==============================================================================
===================A N D T H E Repaired C O D E IS:========================
public class SizeConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length <3 || values[2] == null || values[1] == null || values[0] == null)
return 0;
int numItems = (int)values[2];
int separatorSize = (int)values[1];
double frameSize = System.Convert.ToDouble(values[0]) ;
int totalSeparatorSize = (numItems - 1) * separatorSize;
int remainingArea = System.Convert.ToInt32(frameSize) - totalSeparatorSize;
return remainingArea / numItems;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
In the test case frameSize is a double, not an int. Either change it to int or cast to double in your Convert method.
frameSize is a double.just cast to double
Related
I would like to write a IMultiValueConverter that converts back value (string) to an array with objects compatible with the types given in targetTypes parameter, as so:
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (value != null)
{
List<object> results = new List<object>();
string[] arr = value.ToString().Split(' ');
for (int i = 0; i < arr.Length; i++)
{
object item = (targetTypes[i])arr[i]; //ERROR: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
}
return results.ToArray();
}
else
{
return null;
}
}
So, for example "London 22" I would like to convert back to "London" (string) and "2" (int). As indicated by the list of types in the targetTypes parameter. And of course, return it as an array.
However, I am not able to cast elements of this array to expected by the targetTypes parameter, as I commented in the code above.
The goal is of course to solve the problem reported during binding: "Can not save the value from target back to source.", Which occurs when an attempt is made to store the string to the int.
Which is reported when I use such a converter:
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
if (value != null)
{
return value.ToString().Split(' ');
}
else
{
return null;
}
}
You may try something like this:
public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
var strings = value.ToString().Split(' ');
if (strings.Length != targetTypes.Length)
{
throw new InvalidOperationException("Invalid number of substrings");
}
return strings
.Select((s, i) => System.Convert.ChangeType(s, targetTypes[i]))
.ToArray();
}
i have in my application DatePicker. I would like write standart DateTime format (e.g. 2016-10-18), select DateTime from calendar or write custom format (e.g. ddmmrrrr, ddmm, ddmmrr...)
I made DateTimeConverter:
class DateTimeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime emptyDateTime;
if (DateTime.TryParse(value.ToString(), out emptyDateTime) && emptyDateTime == DateTime.MinValue)
return DateTime.Now;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int valueNumber;
string valueStr = value.ToString().Replace(".", "");
if (!int.TryParse(valueStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out valueNumber))
return DateTime.Now;
if (valueStr.Length == 8) //format ddmmrrrr
{
DateTime emptyDateTime;
//for removing empty datetime (01.01.0001)
return DateTime.TryParse(value.ToString(), out emptyDateTime) && emptyDateTime == DateTime.MinValue
? (object) null
: new DateTime(valueNumber%10000, (valueNumber/10000)%100, valueNumber/1000000);
}
if (valueStr.Length == 6) //format ddmmrr
return new DateTime(2000 + valueNumber % 100, (valueNumber / 100) % 100, valueNumber / 10000);
if (valueStr.Length == 4) //format ddmm
return new DateTime(DateTime.Now.Year, valueNumber % 100, valueNumber / 100);
return DateTime.Now;
}
}
And this is my DatePicker:
<DatePicker Focusable="True" Grid.Column="4"
Text="{Binding Order.DateTime, Mode=TwoWay, Converter={StaticResource DateTimeConverter}}"
PreviewKeyDown="DatePicker_OnPreviewKeyDown"/>
This is property for binding:
class Order{
public DateTime DateTime { get; set; }
}
My problems are:
When DatePicker is null, value in Order.DateTime is 01.01.0001
When I write my format (ddmmrrrr), value in Order.DateTime is DateTime.Now
I dont see whats wrong. Thanks
your Converter checks the TryParse wrong. Change it to:
if (!DateTime.TryParse(value.ToString(), out emptyDateTime) || emptyDateTime == DateTime.MinValue)
return DateTime.Now;
return value;
i get image from client convert it to byte[] and send it to server. And convert byte[] to Base64String and insert into database.
And i do reverse to show image. But i cant see the image. Why???
//Convert to byte array
public static byte[] ImageToByteArray(WriteableBitmap bitmap)
{
int[] p = bitmap.Pixels;
int len = p.Length << 2;
byte[] result = new byte[len];
Buffer.BlockCopy(p, 0, result, 0, len);
return result;
}
//Converter
public object Convert(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture)
{
if (value == null)
{
return null;
}
BitmapImage image = new BitmapImage();
MemoryStream stream = new MemoryStream();
stream.Write((byte[])value, 0, ((byte[])value).Length);
image.SetSource(stream);
return image;
}
//While writing to database
else if (value.GetType() == typeof(byte[]))
{
return "'" + Convert.ToBase64String((byte[])value) + "'";
}
else if ((type == typeof(byte[])))
{
return Convert.FromBase64String((string)value);
}
I have the following code to convert a byte array directly to an image:
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(new MemoryStream(imageData));
newImage.Source = bitmapImage;
So as long as the conversion to and from the Base64String is working this should be all you need.
As an aside, you don't need to convert to a Base64String to store in the database. You just need to set the column type to image (assuming you are using MS SQL Server)
public class Base64StringToImageConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (!(value is string)) return DependencyProperty.UnsetValue;
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(new MemoryStream(System.Convert.FromBase64String((string)value)));
return bitmapImage;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
// TODO: Implement this method
throw new NotImplementedException();
}
}
I used BinaryReader and solved the problem.
My problem was not reading the image correct. iused BinaryReader to read the image and solved the problem.
BinaryReader reader = new BinaryReader(fileInfo.OpenRead());
byte[] tempImage = new byte[reader.BaseStream.Length];
reader.Read(tempImage, 0, tempImage.Length);
I'm grouping some data and PropertyGroupDescription works fine most of the time. However if that property is a DateTime and i wan't to group several dates together as one group (like 30 days in each group or something) I would need a new GroupDescription. Problem is I have no idea how the class actually works and how I would design such a class.
I'm hoping to be able to inherit PropertyGroupDescription (instead of the basic abstract class) because this will also be based on a property but here I'm grouping based on a range of values instead of a single value == 1 group.
Any guide or even a ready class like this?
A bit late, but as you say yourself IValueConverter can be used for this - here's a simple converter I used once that will group by a friendly relative date string:
public class RelativeDateValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var v = value as DateTime?;
if(v == null) {
return value;
}
return Convert(v.Value);
}
public static string Convert(DateTime v)
{
var d = v.Date;
var today = DateTime.Today;
var diff = today - d;
if(diff.Days == 0) {
return "Today";
}
if(diff.Days == 1) {
return "Yesterday";
}
if(diff.Days < 7) {
return d.DayOfWeek.ToString();
}
if(diff.Days < 14) {
return "Last week";
}
if(d.Year == today.Year && d.Month == today.Month) {
return "This month";
}
var lastMonth = today.AddMonths(-1);
if(d.Year == lastMonth.Year && d.Month == lastMonth.Month) {
return "Last month";
}
if(d.Year == today.Year) {
return "This year";
}
return d.Year.ToString(culture);
}
public static int Compare(DateTime a, DateTime b)
{
return Convert(a) == Convert(b) ? 0 : a.CompareTo(b);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can then use it like this:
view.GroupDescriptions.Add(
new PropertyGroupDescription("Property",
new RelativeDateValueConverter()));
I have an enum listing all possible settings:
public enum Settings
{
Settings1,
Settings2,
Settings3
}
In my user control i want to implement a new depedency property that holds a list of settings and be able to use it like this:
<my:Control Settings="Settings1, Settings2" />
How should i implement this?
In your UserControl, make your Dependency property a collection of Settings (perhaps rename your enum to Setting), and then you can populate it in XAML with:
<my:Control>
<my:Control.Settings>
<x:Static Member="my:Setting.Setting1" />
<x:Static Member="my:Setting.Setting2" />
</my:Control.Settings>
</my:Control>
I haven't tested this :)
If you want to stick with a comma separated list, then make your UserControl Settings DP a string, and then on the property changed event handler, split the string and use Enum.Parse on each result to store the settings as your Setting enum type.
public class StringDelimitedToEnumListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
List<Settings> retval = new List<Settings>();
if(value == null || value.GetType() != typeof(string) || targetType != typeof(List<Settings>) )
{
throw new ArgumentException("value must be of type string, target type must be of type List<Settings>");
}
string workingValue = value.ToString();
if (String.IsNullOrEmpty(workingValue))
{
throw new ArgumentException("value must not be an empty string");
}
if (workingValue.Contains(','))
{
string[] tokens = workingValue.Split(',');
foreach (string s in tokens)
{
retval.Add((Settings)Enum.Parse(typeof(Settings), s));
}
return retval;
}
else
{
//there was only 1 value
retval.Add((Settings)Enum.Parse(typeof(Settings),workingValue);
return retval;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//do we care?
throw new NotImplementedException();
}
}