Question:
Good day!
It is necessary to load and unload data from Image into binary data, but I don’t understand how. Previously used to bind to resources or a physical file on disk.
What did I do (the code was written from memory, so there may be typos or some inaccuracies)?
- I created a window in which I placed
Image Source="{Binding myImage, converter={x:static StringToBitmapImageConverter}}"
As you can see, in the myImage property there is a string in base64 format (the data is loaded from XML) and with the help of a converter I bring them to the class format BitmapImage - The converter, if it receives an empty string, or not valid data, loads the default icon from the resources.
- When you click on the picture, a file selection dialog opens, from where I read its binary representation and convert it to string Base64 format
- After opening the file – I do not see the picture (it is not displayed). However, the default image is loaded correctly.
I can't figure out what the problem is.
I will try to give an example of code related to the problematic place (as I think)
Converter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string && targetType != null && targetType.Equals(typeof(ImageSource)))
// здесь я экспериментировал с проверкой типа, по отладке понял, что от окна приходит ImageSource
{
var bitmap = new BitmapImage();
try
{
var buffer = System.Convert.FromBase64String(value as string);
using (var ms = new MemoryStream())
{
// Здесь загрузка проходит, но изображение не появляется на экране
ms.Write(buffer, 0, buffer.Length);
ms.Seek(0, SeekOrigin.Begin);
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
bitmap.CacheOption = BitmapCacheOption.Default;
bitmap.EndInit();
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
}
return bitmap;
}
return GetDefaultBitmapImage(new Uri("pack://application:,,,/Money;Component/Ribbon/Coins/blue.png"));
}
private object GetDefaultBitmapImage(Uri uri)
{
// Здесь загрузка проходит корректно
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = uri;
bitmap.EndInit();
return bitmap;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is BitmapSource && targetType != null && targetType.Equals(typeof(string)))
{
var bitmap = value as BitmapImage;
if (bitmap != null && bitmap.StreamSource.CanRead)
{
byte[] buffer = new byte[bitmap.StreamSource.Length];
var count = bitmap.StreamSource.Read(buffer, 0, buffer.Length);
if (count == buffer.Length)
{
return System.Convert.ToBase64String(buffer, Base64FormattingOptions.InsertLineBreaks);
}
}
}
return string.Empty;
}
Description of the class to which the binding is going
public class CoinViewModel : Vm
{
private Guid _ID;
public Guid ID
{
get => _ID;
set => Set(ref _ID, value, nameof(ID));
}
private string _Front;
public string Front
{
get => _Front;
set => Set(ref _Front, value, nameof(Front));
}
private string _Back;
public string Back
{
get => _Back;
set => Set(ref _Back, value, nameof(Back));
}
public static explicit operator CoinDataView(CoinViewModel vm)
{
return new CoinDataView()
{
ID = vm.ID,
Name = vm.Name,
Count = vm.Count,
SeriaID = vm.SeriaID,
Back = vm.Back,
Front = vm.Front
};
}
}
well, actually, this is how the binding happens
<Image Grid.Column="0" MouseLeftButtonDown="Image_Front_MouseLeftButtonDown" Source="{Binding Front, Converter={StaticResource StringToBitmapImageConverter}}"></Image>
<Image Grid.Column="1" MouseLeftButtonDown="Image_Back_MouseLeftButtonDown" Source="{Binding Back, Converter={StaticResource StringToBitmapImageConverter}}"></Image>
Answer:
Your mistake is that you are freeing the data stream that uses the BitmapImage
, you don't have to do this – remove the using
and just write:
bitmap.StreamSource = new MemoryStream(buffer);