How to convert byte array to image from web API? - c#

My API converts many images to Byte Array and returns the Bytes, but I can't converting again to image. I intend to display in some listview all images from my API.
I tried this but I can't get any image, I was trying to get at least one.
var url = "https://appmaragogi.com.br/api/Files/Upload?Id=ChurrascariaEstreladoMar";
Byte[] imageAsBytes = client.GetByteArrayAsync(url).Result;
MemoryStream stream1 = new MemoryStream(imageAsBytes);
teste.Source = ImageSource.FromStream(() => { return stream1; });
I'd like to show all images in list view, or a way to get all images
i'm using a Image in Xaml to show the Image

You can try to make use of a Converter derived from IValueConverter which could create the image back based on the byte array.
You can refer to my thread of this:
The main code is as follows:
ByteArrayToImageSourceConverter.cs
public class ByteArrayToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ImageSource retSource = null;
if (value != null)
{
byte[] imageAsBytes = (byte[])value;
var stream = new MemoryStream(imageAsBytes);
retSource = ImageSource.FromStream(() => stream);
}
return retSource;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
ImagesModel.cs
public class ImagesModel
{
// other fields
public byte[] PlayerImage { get; set; }
}
xaml(a usage example):
<ContentPage.Resources>
<ResourceDictionary>
<myformapp1:ByteArrayToImageSourceConverter x:Key="ByteArrayToImage" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Margin="5">
<CollectionView x:Name="collectionView"
ItemsSource="{Binding YoudataList}"> <!--changd to your dataList-->
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
x:Name="PlayerPic"
Source="{Binding PlayerImage, Converter={StaticResource ByteArrayToImage}}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="test1"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="test2"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>

I think that only what you need is to save it in a local file, the only thing you have to check is that the format of the image in byte array is fine
File.WriteAllBytes(nameLocalFile, imageAsBytes);

Related

How to write Iconverter for multiple converts

Below is the code which im using to convert the values before binding to the listview. But here only the first 2 converts are working, the results for convert3 and convert4 are not getting displayed.please help me
<ContentPage.Resources>
<local:Class1 x:Key="_converter"/>
</ContentPage.Resources>
<ContentPage.Content>
<ListView x:Name="Models">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding from_time,Converter={StaticResource _converter}}"/>
<Label Text="{Binding to_time,Converter={StaticResource _converter}}"/>
<Label Text="{Binding from_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
<Label Text="{Binding to_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
public class Class1: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var str = (string)value; // value is the binding data
if (str== "00:00:00.0000000")
return "";
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Since it works on the first and second label , I think the issue is caused by the layout . In your case , the StackLayout will not aspect the size of its child elements in runtime .
You could use Grid .
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" HeightRequest="30" Text="{Binding from_time,Converter={StaticResource _converter}}"/>
<Label Grid.Row="1" HeightRequest="30" Text="{Binding to_time,Converter={StaticResource _converter}}"/>
<Label Grid.Row="2" HeightRequest="30" Text="{Binding from_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
<Label Grid.Row="3" HeightRequest="30" Text="{Binding to_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
</Grid>

Image Source Binding Converter doesn't return image from given path [duplicate]

This question already has answers here:
Loading images source dynamically with IValueConverter
(1 answer)
How do I change an image source dynamically from code-behind in WPF with an image in Properties.Resources?
(1 answer)
Closed 4 years ago.
I'm trying to set image source with BitmapImage from converted path
MainWindow.xaml
<local:PathToImageConverter x:Key="PathToImageConverter"/>
<DataTemplate x:Key="GraphicItem">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Height="24" Width="24" HorizontalAlignment="Left" Source="/Handy Clipboard;component/Resources/image.png" />
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding VisibleName}">
<TextBlock.ToolTip>
<Image Source="{Binding Path=ImagePath, Converter={StaticResource PathToImageConverter}}" />
</TextBlock.ToolTip>
</TextBlock>
</StackPanel>
</Grid>
</DataTemplate>
PathToImageConverter Class
public class PathToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Console.WriteLine(value as string); // "Images\image name.png"
return new BitmapImage(new Uri(value as string, UriKind.Relative));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
DataContext of this template is GraphicListItem
public class GraphicListItem : ListItem
{
public ImageSource Content
public string ImagePath
public GraphicListItem() { }
public GraphicListItem(string visibleName, ImageSource content)
public GraphicListItem(string visibleName, ImageSource content, string imagePath)
}
I've tried to bind Content and ImagePath with converter but results are the same - empty tooltip (2x2 px rectangle)
Please help, I don't know even why this isn't working

Show XAML on Condition

The context is I have a Listbox that is outputting items with quite a lot of styling (more than i've put here)... I went to use a DataTemplateSelector to show either one image or another based on a condition but it was stupid to have to re-write the whole tempalte with just this one difference in it.
I have placed some pseudo code to demonstrate what i'm trying to achieve:
<ListBox Grid.Row="1"
ItemsSource="{Binding TestCases}"
BorderThickness="0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Padding="0,5,0,5">
<Run Text="{Binding Class}"></Run>
</TextBlock>
<TextBlock Grid.Column="1"
Padding="5">
<Run Text="{Binding Assertions}"></Run>
</TextBlock>
if {Binding Failures} > 0 {
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Cross.png">
</Image>
}
else
{
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Tick.png">
</Image>
}
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Any ideas on how i do it?
-------------Edit------------
So far i've added the namespace of my converter class to the XAML file:
xmlns:converters="clr-namespace:Blah.Blah.Converters"
Then added window resources:
<Window.Resources>
<converters:FailuresTickConverter x:Key="failuresTickConverter" />
<converters:FailuresCrossConverter x:Key="failuresCrossConverter" />
</Window.Resources>
Then i have the classes themselves:
namespace Blah.Blah.Converters
{
public class FailuresTickConverter : IValueConverter
{
public object Convert( object value, Type targetType,
object parameter, CultureInfo culture )
{
int failures = (int)value;
if( failures > 0 )
return Visibility.Hidden;
return Visibility.Visible;
}
public object ConvertBack( object value, Type targetType,
object parameter, CultureInfo culture )
{
throw new NotImplementedException();
}
}
public class FailuresCrossConverter : IValueConverter
{
public object Convert( object value, Type targetType,
object parameter, CultureInfo culture )
{
int failures = ( int )value;
if( failures > 0 )
return Visibility.Visible;
return Visibility.Hidden;
}
public object ConvertBack( object value, Type targetType,
object parameter, CultureInfo culture )
{
throw new NotImplementedException();
}
}
}
Then in my XAML on the images i've done this:
<Image Visibility="{Binding Failures, Converter=failuresTickConverter}"
HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Grid.Row="0"
Source="/Content/Images/Tick.png">
</Image>
<Image Visibility="{Binding Failures, Converter=failuresCrossConverter}"
HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Grid.Row="0"
Source="/Content/Images/Cross.png">
</Image>
I'm getting an error on the bindings:
IValueConverter does not support converting from string
Elaborating on my comment, here's a simple (not the only one, of course) way to do it:
Create a converter to convert number to visibility:
public class PositiveToVisibilityConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (int)value > 0 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add the namespace of the converter to your xaml, add the converter to resources (use your own namespace of course):
<Window ...
xmlns:converters="clr-namespace:WpfApplication1.Converters"
...>
<Window.Resources>
<converters:PositiveToVisibilityConverter x:Key="PositiveConverter"/>
</Window.Resources>
Then put both the images in, the "success" one first and bind the property using the converter to the "failure" one:
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Tick.png"
Visibility="{Binding Failures, Converter={StaticResource PositiveConverter}}">
</Image>
<Image HorizontalAlignment="Center"
Width="10"
Height="10"
Grid.Column="2"
Source="/Content/Images/Cross.png">
</Image>
Since these images are in a grid (I assume) and have the same position and size, they will overlap and normally the one that's defined last will be drawn last, so the first one will not be visible. That is, unless the binding makes the second image invisible.

Image not visible when setting source to ValueConverter

I'm trying to change an Image in a LongListSelector on basis of a boolean property of the DataContext of the LongListSelector. I'm using a ValueConverter in order to achieve this, and the code does reach the ValueConverter and returns a BitmapImage but this isn't visible on screen. Here's some of the relevant code:
XAML code (ItemTemplate and the ValueConverter declaration):
<local:BoolToImage x:Key="BoolImageConverter"/>
DataTemplate x:Key="itemTemplate">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Foreground="Black" Margin="0" FontFamily="Segoe WP Light" FontSize="29.333" VerticalAlignment="Center" Text="{Binding BeginTijdTimeOnly}" />
<TextBlock Grid.Column="1" TextWrapping="Wrap" Foreground="Black" Margin="0" FontFamily="/LimburgsLeed;component/Fonts/Fonts.zip#Champion" FontSize="48" VerticalAlignment="Center" Text="{Binding Artiest.Naam}" />
<Image x:Name="image" Grid.Column="2" Source="{Binding Path=isSaved, Converter={StaticResource BoolImageConverter}}" VerticalAlignment="Center" Margin="0, 0, -1, 0" MouseLeftButtonDown="fav_Click"/>
</Grid>
</DataTemplate>
As you can see the Image is bound to the ValueConverter and the isSaved property.
ValueConverter code:
public class BoolToImage : IValueConverter
{
public BitmapImage TrueImage = new BitmapImage();
public BitmapImage FalseImage = new BitmapImage();
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TrueImage.UriSource = new Uri("/Images/ThumbSelected#2x.png", UriKind.RelativeOrAbsolute);
FalseImage.UriSource = new Uri("/Images/thumb.png", UriKind.RelativeOrAbsolute);
if (!(value is bool))
{
return this.FalseImage;
}
bool b = (bool)value;
if (b)
{
return this.TrueImage;
}
else
{
return this.FalseImage;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I don't have a clue why the image isn't shown.. The ValueConverter CAN'T return null.
My god, I sure feel stupid now. This all works fine, but I set the Image files their Build Action to Embedded Resource. Changing it to content resolved the problem.

How to convert back from string to Enum

I have a a class which is made of property information of a target(like type and values ). Iam using this UI to show all types on view in graphical format like Enum with comboboxes and boolean with checkboxes.Everything works well for me except the case when I change combobox value in UI,it does not change in viewmodel.Every time I change value in combobox it calls convertback method in my converter.I need to convert this string to enum type,I can write the convertback code easily for a particular enum type ,but how can I convert all other enums with this converter,I have the information of Type in PropertyType property that I can pass to converter and use it but I have no idea how to do it.
This is my UI code (only relevant part)
<!-- Default DataTemplate -->
<DataTemplate x:Key="DefaultDataTemplate">
<Grid Margin="4" MinHeight="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<TextBox Margin="8,0" Grid.Column="1" Text="{Binding Value}" />
</Grid>
</DataTemplate>
<!-- DataTemplate for Booleans -->
<DataTemplate x:Key="BooleanDataTemplate">
<Grid Margin="4" MinHeight="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<CheckBox Margin="8,0" Grid.Column="1" IsChecked="{Binding Value}" />
</Grid>
</DataTemplate>
<!-- DataTemplate for Enums -->
<DataTemplate x:Key="EnumDataTemplate">
<Grid Margin="4" MinHeight="25">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Key" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" FontWeight="Bold" />
<ComboBox Margin="8,0" SelectedItem="{Binding Value,Converter={StaticResource EnumToStringConverter},Mode=TwoWay}"
ItemsSource="{Binding PropertyType,
Converter={local:EnumToListConverter}}" Grid.Column="1"
HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
<!-- DataTemplate Selector -->
<local:PropertyDataTemplateSelector x:Key="templateSelector"
DefaultnDataTemplate="{StaticResource DefaultDataTemplate}"
BooleanDataTemplate="{StaticResource BooleanDataTemplate}"
EnumDataTemplate="{StaticResource EnumDataTemplate}"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ListView Grid.Row="0" ItemsSource="{Binding Model,Converter={StaticResource PropConverter}, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Grid.IsSharedSizeScope="True"
HorizontalContentAlignment="Stretch"
ItemTemplateSelector="{StaticResource templateSelector}"
/>
and my converter and view model
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string EnumString;
try
{
EnumString = Enum.GetName((value.GetType()), value);
return EnumString;
}
catch
{
return string.Empty;
}
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return null;
//What to do here
}
View model
public class PropertyValue
{
private PropertyInfo propertyInfo;
private object baseObject;
public PropertyValue(PropertyInfo propertyInfo, object baseObject)
{
this.propertyInfo = propertyInfo;
this.baseObject = baseObject;
}
public string Name
{
get { return propertyInfo.Name; }
}
public Type PropertyType { get { return propertyInfo.PropertyType; } }
public object Value
{
get { return propertyInfo.GetValue(baseObject, null); }
set
{
propertyInfo.SetValue(baseObject, value , null);
}
}
}
Try
return (targetType)Enum.Parse(typeof(targetType), value.ToString());
In ConvertBack, is targetType the correct enum type?
If so, I think this should work:
Enum.Parse(targetType, (String)value)
you shoud do it like this
enum Colors { Red = 1, Green = 2, Blue = 4, Yellow = 8 };
string colorName = "Blue";
if (Enum.IsDefined(typeof(Colors), colorName)) //true
{
Colors clr = (Colors)Enum.Parse(typeof(Colors), colorName);
}
colorName = "Orange";
if (Enum.IsDefined(typeof(Colors), colorName)) //false
{
Colors clr = (Colors)Enum.Parse(typeof(Colors), colorName);
}
I dont think its feasible to do this with converter or with multibinding.I solved my problem by not using the converter for combobox and checking value in getter and setter.
I modified my class which holds the property info and it works now,I am putting a special check for enum type ,rest of the types I can use converters.
public class PropertyValue
{
private PropertyInfo propertyInfo;
private object baseObject;
public PropertyValue(PropertyInfo propertyInfo, object baseObject)
{
this.propertyInfo = propertyInfo;
this.baseObject = baseObject;
}
public string Name
{
get { return propertyInfo.Name; }
}
public Type PropertyType
{
get { return propertyInfo.PropertyType; }
}
public object Value
{
get
{
var retVal = propertyInfo.GetValue(baseObject, null);
if (PropertyType.IsEnum)
{
retVal = retVal.ToString();
}
return retVal;
}
set
{
if (PropertyType.IsEnum)
{
value = Enum.Parse(propertyInfo.PropertyType, value.ToString());
}
propertyInfo.SetValue(baseObject, value, null);
}
}
}
I dont like corrupting view model for that but I cant see any option at this moment.Please let me know if there are any risks in my code or if you have a better approach.
What I could think quickly is that you can create one class EnumDescriptor with just two properties: EnumString (string) and EnumType (Type)
Your "EnumToListConverter" can return list of EnumDescriptor and you can bind display value of combobox to EnumString property.
In your "EnumToStringConverter", in Convert() you can create instance of EnumDescriptor as we have type and name of enum there, in ConvertBack() you will get the instance of EnumDescriptor from where you can parse the enum value and return it.
Thanks

Categories

Resources