So I have an Image in the View which is bound to byte array in the ViewModel.
<Image
Source="{ Binding InputImage, Converter={StaticResource imageConvertor}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Panel.ZIndex="1"
x:Name="UploadImage"
Grid.Column="0"
Grid.Row="0"
Stretch="Uniform"
Margin="5"
/>
private byte[] inputImage;
public byte[] InputImage
{
get { return inputImage; }
set
{
inputImage = value;
OnPropertyChanged(nameof(InputImage));
}
}
The user uploads an image from their fails via button which executes this command
OpenFileDialog op = new OpenFileDialog();
op.Title = "Select a picture";
op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|"
"JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|"
"Portable Network Graphic (*.png)|*.png";
if (op.ShowDialog() == true)
{
UploadImage.Source = new BitmapImage(new Uri(op.FileName));
}
The problems is that when I try to upload an image the the converter receives null as parameter. If I remove the converter from the binding in the xaml file it gets uploaded successfully to the view but it cannot be bound to the property in the ViewModel.
This is the implementation of the converter
public class ByteArrayToBitmapImageConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
else
return ToImage(value as byte[]);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
else
return ToBinary(value as Image);
}
public static Image ToImage(Byte[] binary)
{
Image image = null;
if (binary == null || binary.Length < 100) return image;
using (MemoryStream ms = new MemoryStream(binary))
{
image = Image.FromStream(ms);
}
return image;
}
public static Byte[] ToBinary(Image image)
{
if (image == null) return null;
using (MemoryStream memoryStream = new MemoryStream())
{
image.Save(memoryStream, ImageFormat.Png);
return memoryStream.ToArray();
}
}
}
What causes the null inputs
CodePudding user response:
You are using the WinForms Image class instead of the WPF BitmapSource
. BitmapSource is a subclass of ImageSource, which is the type of the Image element's Source
property.
Your converter should look like this:
public class ByteArrayToBitmapImageConverter : IValueConverter
{
public object Convert(
object value, Type targetType, object parameter, CultureInfo culture)
{
return ToBitmapSource(value as byte[]);
}
public object ConvertBack(
object value, Type targetType, object parameter, CultureInfo culture)
{
return ToByteArray(value as BitmapSource);
}
public static BitmapSource ToBitmapSource(byte[] buffer)
{
if (buffer == null)
{
return null;
}
using (var stream = new MemoryStream(buffer))
{
return BitmapFrame.Create(
stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
}
public static byte[] ToByteArray(BitmapSource bitmap)
{
if (bitmap == null)
{
return null;
}
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var stream = new MemoryStream())
{
encoder.Save(stream);
return stream.ToArray();
}
}
}
It would however be a lot simpler to directly assign the frame buffer from the image file to the view model property like
viewModel.InputImage = File.ReadAllBytes(op.FileName);
You would not need your converter at all, because due to built-in type conversion, the Image.Source
property can directly be bound to source properties of type string
, Uri
and byte[]
(besides ImageSource
).