I'm working with Xamarin Forms and I want to load a listview with imagecells, also I'm binding the data with XAML.
My webservice provider returns me the binary code of the images, ¿someone knows how I can convert this to show the image?
This is my XAML listview template:
<ListView x:Name="lv_products">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell
Text="{Binding Name}"
Detail="{Binding Description}"
ImageSource="{Binding Image, Converter={StaticResource cnvImage}}">
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && value is byte[])
{
byte[] binary = (byte[])value;
Image image = new Image();
image.Source = ImageSource.FromStream(() => new MemoryStream(binary));
return image.Source;
}
return null;
}
But picture appears empty (transparent).
Here is working converter. I use MemoryStream and ImageSource.FromStream.
public class ByteImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var image = value as byte[];
if (image == null)
return null;
return ImageSource.FromStream(() => new MemoryStream(image));
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Just as sample here is my page
public partial class Page : ContentPage
{
readonly ViewModel _bindingContext = new ViewModel();
public Page()
{
InitializeComponent();
BindingContext = _bindingContext;
LoadImage();
}
private async void LoadImage()
{
var assembly = typeof (ByteImageConverter).GetTypeInfo().Assembly;
var stream = assembly
.GetManifestResourceStream("TestImage.c5qdlJqrb04.jpg");
using (var ms = new MemoryStream())
{
await stream.CopyToAsync(ms);
_bindingContext.Image = ms.ToArray();
}
}
}
public class ViewModel : INotifyPropertyChanged
{
private byte[] _image;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(
[CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public byte[] Image
{
get { return _image; }
set
{
_image = value;
OnPropertyChanged();
}
}
}
If you have a URL which returns the image file, why aren't you just use the URL as ImageSource ?
<ImageCell Text="{Binding Name}"
Detail="{Binding Description}"
ImageSource="{Binding ImageURL}">
</ImageCell>
You can convert byte array to Bitmap image, and assign that bitmap to the ImageView. I did this in Xamarin.Android, dnt know will it work with forms or not.
bitmap = BitmapFactory.DecodeByteArray(byte, 0, byte.Length);
Then use imageView.FromBitmap() to display this image.
Related
I would like to partially mask the password field from dots to asterisk. I tried using a converter but it doesn't work. What is the best way to achieve this in xamarin forms.
<Entry IsPassword="True"
Placeholder="password"
Text="{Binding Password.Value, Mode=TwoWay, Converter={StaticResource
MaskedPasswordConverter}}"
MaxLength="6">
public class MaskedPasswordConverter : IValueConverter
{
private string _value;
public object Convert(object value, Type targetType, object parameter, CultureInfo
culture)
{
var str = (value ?? "").ToString();
_value = str;
var maskedStr = "";
if (!string.IsNullOrEmpty(str) && str.Length > 2)
{
var domainStr = str.IndexOf('#');
var lengthOfMask = domainStr - 2;
maskedStr = str.Substring(0, 2) + new string('*', lengthOfMask) +
str.Substring(domainStr);
}
return maskedStr;
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return value;
}
}
I suggest you use behaviors for this.
You can find out more about Xamarin forms behaviors here
More examples here
Hope this helps.
If you want to use IValueConverter to mask partial password using asterisk, I think you can set binding mode as OneWay, then please confirm that there is # character in your Password.
I suggest you can use this way to mask email, don't mask password, but you still want to do ,this is the sample that you can take a look:
<Entry
MaxLength="6"
Placeholder="password"
Text="{Binding password, Mode=OneWay, Converter={StaticResource converter1}}" />
public partial class Page24 : ContentPage, INotifyPropertyChanged
{
private string _password;
public string password
{
get
{ return _password; }
set
{
_password = value;
RaisePropertyChanged("password");
}
}
public Page24()
{
InitializeComponent();
password = "123#56";
this.BindingContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
IValueConverter:
public class Passwordconverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var str = (value ?? "").ToString();
var maskedStr = "";
if (!string.IsNullOrEmpty(str) && str.Length > 2)
{
var domainStr = str.IndexOf('#');
var lengthOfMask = domainStr - 2;
maskedStr = str.Substring(0, 2) + new string('*', lengthOfMask) + str.Substring(domainStr);
}
return maskedStr;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
This is the screenshot:
But I still suggest you can use custom render to mask your password using asterisk, this is the sample about this, you can take a look:
How to change password masking character in Xamarin forms - Entry
I'm trying to get SkiaSharp working with Xamarin Forms and Prism. I have it working with the following page behind code
public partial class RoomLayoutPage : ContentPage
{
SKCanvasView canvasView;
public RoomLayoutPage()
{
InitializeComponent();
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint blackPaint = new SKPaint
{
Color = SKColors.Black,
};
canvas.DrawRect(0, 0, 100, 100, blackPaint);
}
}
but now I want to move this to my Prism ViewModel. If I move it then Content is not valid
How do I reference a xaml element from a ViewModel? I'd prefer not to do it this way because my ViewModel is then coupled to the view.
(Prefered way) If I put an SKCanvasView on my page
I can bind to the event with the EventToCommandBehaviour
<forms:SKCanvasView>
<forms:SKCanvasView.Behaviors>
<behaviors:EventToCommandBehavior Command="{Binding OnCanvasViewPaintSurface}" EventName="PaintSurface"/>
</forms:SKCanvasView.Behaviors>
</forms:SKCanvasView>
But I'm not sure how to bind the SKPaintSurfaceEventArgs for
OnCanvasViewPaintSurface = new DelegateCommand<SKPaintSurfaceEventArgs>(OnCanvasViewPaintAction);
I'm assuming it's one of the EventArgs options from here https://prismlibrary.github.io/docs/xamarin-forms/EventToCommandBehavior.html ?
Thank you
So using a value converter solves it..
public class SkiaEventArgsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var sKPaintSurfaceEventArgs = value as SKPaintSurfaceEventArgs;
if (sKPaintSurfaceEventArgs == null)
{
throw new ArgumentException("Expected value to be of type SKPaintSurfaceEventArgs", nameof(value));
}
return sKPaintSurfaceEventArgs;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Not entirely sure why it couldn't convert it automagically but it works
i am using Button as beow to show the add to cart button with image in the xaml view
<Button x:Name="cartbutton" Grid.Row="0" Command="{Binding Source={x:Reference ListItemPage}, Path=BindingContext.CartCommand}" CommandParameter="{Binding .}" HorizontalOptions="End" VerticalOptions="Start" Image="lowim.png" BackgroundColor="Transparent" Margin="0,5,5,0" />
and use in the MVVM inside the constructor as below
CartCommand = new Command<Resturent>(OnCartCommand);
then i am using MVVM with dependency injection where i only get the Icommand of the button click in the view model as below
public ICommand CartCommand { get; set; }
public async void OnCartCommand(Resturent restoraunt)
{
await DialogService.DisplayAlert("CART DETAILS", "ITEM"+ restoraunt.Name+ "SUCESSFULLY ADDED", "OK");
}
i am expecting to create a toggle button where when i click on the button ( where the user add the items to the cart by pressing button with image lowim.png as shown above) then the image of the button suppose to change ( with another image icon lets say add.jpg). support in this regard will be highly appreciated and thank you advance for your support.
Well, all you have to do is create a converter something like this:
public class ConverterAddRemoveImage : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool isAddedToCart = (bool)value;
if (isAddedToCart)
{
return "PositiveImage"; //This will be a string
}
else
{
return "NegativeImage"; //This will be a string
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you need to define it in the XAML resource dictionary of your XAML page something like this:
<ContentPage.Resources>
<ResourceDictionary>
<common:ConverterAddRemoveImage x:Key="AddRemoveImage" />
</ResourceDictionary>
</ContentPage.Resources>
Where common is the namespace where your converter is present.
The image source would be something like this:
Source="{Binding IsAddedToCart, Converter={StaticResource AddRemoveImage}}
Where is added to cart is a bool property in your model something like this :
private bool isInCart;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsAddedToCart
{
get
{
return isInCart;
}
set
{
isInCart= value;
NotifyPropertyChanged(nameof(IsAddedToCart));
}
}
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Note: Your model class must inherit from INotifyPropertyChanged interface
Now, as soon as you change your model bool property it will change the image accordingly.
Goodluck revert in case of any queries
i want to bind a list of images to a stackpanel which is inside a DataGrid.RowDetailsTemplate.
My class structure is as follows:
public class A
{
private List<MyImage> _images = new List<MyImage>();
public List<MyImage> Images { get; set; }
public string Name { get; set; }
public void AddImage(byte[] src) { ... }
}
public class MyImage
{
public BitmapImage Image { get; set; }
public byte[] RawData { get; set; }
}
In my main class i have a list of A:
public List<A> AList { get; set; }
dataGrid1.ItemsSource = AList;
dataGrid1.DataContext = AList;
All i want to do is to display the Name property of an element in a DataGridTextColumn and all images stored in the Images property in the RowDetails.
My xaml is:
<DataGrid name="dataGrid1">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Path=Name}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel DataContext="{Binding Path=Images}">
<Image Source="{Binding Path=RawData}"/>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
All i get to see is just one image although there are some more stored in Images. Any ideas?
Ok, so the solution of this problem was the use of ContentPresenter combined with a converter.
Now my XAML looks like this:
<DataGrid name="dataGrid1">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Path=Name}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Images, Converter={StaticResource ImageCollectionConverter}}"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
And the corresponding converter class:
public class ImageCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
List<MyImage> images = value as List<MyImage>;
if (images != null)
{
StackPanel stack = new StackPanel();
stack.Orientation = Orientation.Horizontal;
foreach (DesignImage img in images)
{
Image image = new Image();
image.Source = img.Image;
stack.Children.Add(image);
}
return stack;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Db class propertys
[Serializable]
[EnableClientAccess()]
public class DbPersonelJobDetail
{
public DbPersonelJobDetail()
{
}
[Key]
public Guid PersonelID { get; set; }
public Guid JobID { get; set; }
public string JobName { get; set; }
public string Adi { get; set; }
}
DomainServices Linq Query
public IQueryable<DTO.DbPersonelJobDetail> GetPersonelJobTreeList()
{
IQueryable<DTO.DbPersonelJobDetail> result = from p in ObjectContext.SPA_PersonelJobDetail
join c in ObjectContext.SPA_PersonelJob on p.PersonelJobID equals c.ID
select new DTO.DbPersonelJobDetail()
{
JobID=p.PersonelJobID,
JobName = c.JobName,
PersonelID=p.ID,
Adi=p.Adi
};
return result.AsQueryable();
}
BindTreeList methot
public void BindTreeList()
{
loadOP = context.Load(context.GetPersonelJobTreeListQuery(), false);
loadOP.Completed += loadOP_Completed;
}
void loadOP_Completed(object sender, EventArgs e)
{
treeListPersonel.ItemsSource = loadOP.Entities;
}
I'm Treeview of binding BindTreeList() methot.
The following, as in the picture. HierarchicalDataTemplate Itemsource binding howto?
Could you make an example?
I could not :(
Waiting for your ideas...
Pucture
Load first lavel nodes.
In HierarchicalDataTemplate bind ItemsSource to LoadChildsConverter
<riaControls:DomainDataSource x:Name="MyData" QueryName="GetFirstLavel"
AutoLoad="True" LoadSize="50">
<riaControls:DomainDataSource.DomainContext>
<web:AdvDomainContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<sdk:TreeView ItemsSource="{Binding}" DataContext="{Binding ElementName=MyData, Path=Data}">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate
ItemsSource="{Binding Converter={StaticResource TreeViewCollectionConverter}}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CODE}" />
<TextBlock Text="{Binding DESC}" />
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</sdk:TreeView>
TreeViewCollectionConverter.cs
public class TreeViewR5OBJECTCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ObservableCollection<Node> nodeList = new ObservableCollection<Node>();
if (value != null)
{
AdvDomainContext ctx = new AdvDomainContext();
Node parentNode = (Node)value;
ctx.Load(ctx.GetChildsQuery(parentNode), iop =>
{
foreach (var o in iop.Entities)
nodeList.Add(o);
}, null);
}
return nodeList;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
In AdvDomainService.cs
must have
public IQueryable<Node> GetFirstLavel()
to return first level nodes
and
public IQueryable<Node> GetChilds(Node ParentNode)
to return childs of ParentNode