Am having a scenario , where i have a BaseImageUrl String
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
for the images i want to retrieve into the Image view in Xaml plus concatenating it with a string value office_photo which has the exact image name forexample flower.jpg and is got after deserializing JSON and it comes as a List , below is my Model class :
public class Adverts
{
public string office_photo { get; set; }
public DateTime entryDate { get; set; }
}
so what i want is how to concatenate the BaseUrl and office_photo in XAML so that i get the complete link to images .
below is my Image in the ListView :
<ListView x:Name="listViewTest" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Aspect="AspectFill" Source="{Binding office_photo}" x:Name="advertImage"
WidthRequest="200"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Just concatenate the two strings in a new property in your view modem and bind to that property. It's really simple and one line of code :-)
Something like this:
public string PhotoUrl { get { return BaseImageUrl + office_photo; }}
Use a IValueConverter
Something like
public class AddBaseUrlConverter : IValueConverter
{
#region IValueConverter implementation
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && ! string.IsNullOrEmpty((string)value)) {
return string.Format("{0}{1}", BaseImageUrl, (string)value);
}
return ""; //
}
public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ();
}
#endregion
}
Then in your XAML something like
<ContentPage.Resources>
<ResourceDictionary>
< AddBaseUrlConverter x:Key="cnvInvert"></AddBaseUrlConverter >
</ResourceDictionary>
</ContentPage.Resources>
<Image Aspect="AspectFill" Source="{Binding office_photo, Converter={StaticResource cnvInvert}}" x:Name="advertImage" WidthRequest="200"/>
(not tested, but it could work)
Related
I would really like to know how I can bind an ImageSource to a specific element's property in an ObservableCollection... Right now I have this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyNameSpace"
x:Class="MyNameSpace.MainPage"
x:Name = "Main"
Padding="5,20,5,5"
BindingContext="{x:Reference Name=Main }">
<Grid
<ImageButton
Grid.Column="0"
Grid.Row="0"
Source="{Binding _hand[0].ResourceId , Converter={StaticResource
StringToSourceConverter}}"
>
</ImageButton>
<ImageButton
Grid.Column="1"
Grid.Row="0"
Source="{Binding _hand[1].ResourceId , Converter={StaticResource
StringToSourceConverter}}"
>
</ImageButton>
<ImageButton
Grid.Column="0"
Grid.Row="1"
Source="{Binding _hand[2].ResourceId , Converter={StaticResource
StringToSourceConverter}}"
>
</ImageButton>
<ImageButton
Grid.Column="1"
Grid.Row="1"
Source="{Binding _hand[3].ResourceId , Converter={StaticResource
StringToSourceConverter}}"
>
</ImageButton>
</Grid>
</ContentPage>
I would like to bind the ImageSource to the following ObservableCollection of Cards...
public partial class MainPage : ContentPage, INotifyPropertyChanged
{
private ObservableCollection<Card> _hand;
public MainPage()
{
Init();
InitializeComponent();
}
private void Init()
{
_hand = new ObservableCollection<Card>()
{
new Card("image1.jpg"),
new Card("image2.jpg"),
new Card("image3.jpg"),
new Card("image4.jpg")
};
}
}
My Card class looks something like this:
public Card ( string resourceId)
{
ResourceId = resourceId;
}
public string ResourceId { get; set; }
The Converter used :
public class ToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string ResourceId = value.ToString();
if (String.IsNullOrWhiteSpace(ResourceId))
return null;
return ImageSource.FromResource(ResourceId);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
My question now is how do I make this code work? Also I have methods that switch elements in the collection. Where do I implement PropertyChangedEvent? Thank you guys a lot :)
I have a ListView in XAML and a List<string> that holds local embedded image paths. I am not able to show images in List. By the way I am able to show as a single image by
<Image Source="{local:ImageResource TypingApplication.Images.Icons.Search.png}" />
But I cannot show the images in ListView. Here is my XAML code
<ListView x:Name="ListView"
ItemsSource="{Binding ListItems}"
IsEnabled="True"
IsVisible="True"
RowHeight="40"
Opacity="0.9">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{local:ImageResource TypingApplication.Images.Icons.{Binding .}}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have added ImageResourceExtension in Extensions folder and xmlns:local="clr-namespace:TypingApplication.Extensions" in XAML, as I mentioned I can show Single Image, only there is problem with ListView.
Here is my C# code that contains List and Constructor
public List<string> ListItems
{
get
{
return new List<string>()
{
"Home.png",
"Favorite.png",
"Search.png"
};
}
}
public HomePage()
{
InitializeComponent();
this.BindingContext = this;
}
Please note that I am using shared Images in my project. I have set Properties of all Images to Embedded resource in SolutionExplorer.
Change list to ObservableCollection
IValueConverter implementation to convert your binding to desired value
The image property should be set to EmbeddedResource
public class EmbeddedToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string fileName && parameter is String assemblyName)
{
try
{
var imageSource = ImageSource.FromResource(assemblyName + "." + fileName, typeof(EmbeddedToImageSourceConverter).GetTypeInfo().Assembly);
return imageSource;
}
catch (Exception)
{
return value;
}
}
else
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
XAML
<ContentPage.Resources>
<local:EmbeddedToImageSourceConverter x:Key="converter" />
</ContentPage.Resources>
In the listview add binding w.r.to converter resource we just created.
<Image Source="{Binding ., Converter={StaticResource converter}, ConverterParameter='TypingApplication.Images.Icons'}" />
If you are not using View Model (MVVM), you can directly specify image file's name in XAML as:
<Image Source="{Binding Source='ImageFileName.png', Converter={StaticResource converter}, ConverterParameter='TypingApplication.Images.Icons'}" />
If you want to add Embedded image in listview, according to json's reply, your binding have some problem, you can use IValueConverter to convert image path as correct.
I do one sample according to your code, you can take a look:
<ListView HasUnevenRows="True" ItemsSource="{Binding ListItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Image
HeightRequest="100"
Source="{Binding ., Converter={StaticResource imageconverter}}"
WidthRequest="100" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ContentPage.Resources>
<local:imageconverter x:Key="imageconverter" />
</ContentPage.Resources>
The Image converter:
public class imageconverter : IValueConverter
{
public string Source { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Source = (string)value;
if (Source == null)
return null;
// Do your translation lookup here, using whatever method you require
var imageSource = ImageSource.FromResource("demo3."+Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
return imageSource;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can change demo3 as TypingApplication according to your code.
public partial class Page14 : ContentPage
{
public ObservableCollection<string> ListItems { get; set; }
public Page14()
{
InitializeComponent();
ListItems = new ObservableCollection<string>()
{
"image1.jpg","image2.png","image3.png"
};
this.BindingContext = this;
}
}
As Prateek's reply, I suggest you can change List<> to Observablecollection<>, because it implement INotifyPropertyChanged interface, notify data changed.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netframework-4.8
Very simplified version of my code:
ViewModels:
public class ViewModel
{
public ObjectViewModel {get; set;}
}
public class ObjectViewModel
{
public string MyString {get; set;}
public bool MyStringIsValid {get; set;}
}
Xaml:
<Entry Text="{Binding ObjectViewModel.MyString}" TextChanged="Entry_TextChanged"/>
<Label Text="Valid!" IsVisible="{Binding ObjectViewModel.MyStringIsValid}"/>
In my code behind, I would like to be able to grab the bound property of Entry.Text by doing something like this:
void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
//Psuedocode
//ObjectViewModel ovm = (sender as Entry).Text.Binding.Source;
}
The reason I want to do this is to perform validation on "MyString" and change its "MyStringIsValid" property if necessary. My question is how do I do this and if it isn't possible, can you recommend a better approach?
In my real code I have used INotifyPropertyChanged to update the view according to viewModel changes, but I have omitted this for brevity.
Thanks!
I guess all you need is a Converter. I don't know why you need to maintain a property for changing the IsVisible based on the validation of a text. The below code works for me for a similar scenario which you mentioned.
<!--Declare the namespace at the top of the XAML-->
xmlns:c="clr-namespace:Demo.Helper"
<!--Register your Converter in the Resources-->
<ContentPage.Resources>
<ResourceDictionary>
<c:TextToBoolConverter x:Key="textToSpeechConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Entry x:Name="entry1" Text="{Binding ObjectViewModel.MyString}" />
<Label Text="Valid!" IsVisible="{Binding Text, Source={x:Reference entry1}, Converter={StaticResource textToSpeechConverter}}"/>
Below is the converter code which I tested.
public class TextToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string stringValue = value?.ToString();
if (!string.IsNullOrEmpty(stringValue))
return true;
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
When I run the app, on first up page instead Entrys are showing default text 0 instead of placeholder.
I have AddContactPage.xaml
<StackLayout>
<Entry Placeholder="Enter Class" Text="{Binding Class}"></Entry>
<Entry Placeholder="Enter Id" Text="{Binding StudentId}"></Entry>
</StackLayout>
Attributes binded to Entries
public int StudentId { get; set; }
public int Class { get; set; }
How can I solve this issue. See o/p-
Actually you can use StringFormat. Try this
StringFormat='{0:#.##;;}'
One possible solution is a string property for binding:
private int _studentId;
public int StudentId
{
get { return _studentId; }
set
{
SetProperty(ref _studentId, value);
RaisePropertyChanged("StudentIdString"); // If you're using Prism. You can use any other way to raise the PropertyChanged event
}
}
public string StudentIdString
{
get { return StudentId.ToString(); }
}
That's it! Now you can bind StudentIdString to your Entry. Do the same with Class and you're good to go.
Another solution to your problem is a converter as Woj suggested:
public class IntToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int i = (int)value;
return i.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return int.Parse((string)value);
}
}
Then use it in your xaml like this:
<ContentPage.Resources>
<ResourceDictionary>
<local:IntToStringConverter x:Key="intToString" />
</ResourceDictionary>
</ContentPage.Resources>
<Entry Placeholder="Enter Id" Text="{Binding StudentId, Converter={StaticResource intToString}}"></Entry>
Since the Entry control Text is binded to a model, it will not show a place holder for a null property which is associated. You may need to remove the Text binding in that case.
My Model is
class MainPageList
{
public string item { get; set; }
public List<string> sitem { get; set; }
public List<string> ssitem { get; set; }
}
and My View Model is
class MainPageViewModel
{
public List<MainPageList> MList {
get{
return new List<MainPageList>
{
new MainPageList(){item="Item1",sitem= new List<string>{"sub item1","sub item2","sub item3"}, ssitem= new List<string>{"sub sub item1","sub sub item2","sub sub item3"}}
};
}
}
public string item { get; set; }
public List<string> sitem { get; set; }
public List<string> ssitem { get; set; }
}
and XAML is
<StackLayout>
<Label Text="Introcduction Page" Font="18" />
<ListView x:Name="MainPageList" ItemsSource="{Binding MList} " >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding item} "></Label>
<StackLayout Padding="10,10,0,0">
<Label Text="{Binding sitem} "></Label>
<StackLayout Padding="10,10,0,0">
<Label Text="{Binding ssitem} "></Label>
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I can get the text for sitem but sitem and ssitem are not being displayed in Emulator or Device.
Any help appreciated in advance, please.
You can't bind a List to a StackLayout and have it automatically "inflate" the data. You can either use a ListView (which will apply a template to each item in the List) or manually build the collection of child objects that you want to display in your StackLayout.
You can't bind a list into a Label. It should be a primitive type or a Class which implements ToString() method. If you want to show all items into a Label you can write a Converter like:
public class ListToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if(value is IEnumerable)
{
string retval ="";
for(string item in (IEnumerable)value) //use your string format here
retval+= item+",";
return retval;
}
else
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
and use it on WPF side:
<!--define static resource -->
<ContentPage.Resources>
<ResourceDictionary>
<Converters:ListToString x:Key="ListToString"/>
</ResourceDictionary>
</ContentPage.Resources>
<!--use it -->
<Label Text="{Binding sitem,Converter={StaticResource ListToString}} "></Label>