Xamarin Forms Dynamic bind image in a ViewCell - c#

I'm in trouble with dynamic bind of images in a ViewCell. I have a shared project for Android and iOS. My ViewCell is so defined
<ViewCell>
<StackLayout Padding="5" Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image WidthRequest="32" HeightRequest="32" Source="{Binding Image}"></Image>
<Label Text="{Binding Source}" FontSize="Medium" TextColor="#003056"></Label>
</StackLayout>
...
The Image property is so defined in the class
public ImageSource Image {
get
{
ImageSource imageSource = ImageSource.FromResource("MyProject.Images.image001.png");
return imageSource;
}
The Images folder is in the shared project.
The imageSource returned is not null, there are no errors but the images is not shown.
Can you help, plese?
Thanks

Ensure each image has Build option set to Embedded Resource using Properties menu(right click) as described here: https://developer.xamarin.com/guides/xamarin-forms/user-interface/images/

Related

ToolbarItems icon not showing up

how to add an icon before the text "Share"?
below code only displays text and not icon. I have added icon into drawable folder
<ContentPage.ToolbarItems>
<ToolbarItem Name="Share" Order="Secondary" IconImageSource="icon_share.png" Icon="icon_share.png" Priority="0" />
<ToolbarItem Name="Delete" Order="Secondary" IconImageSource="icon_delete.png" Icon="icon_delete.png" Priority="1" />
</ContentPage.ToolbarItems>
The icon for Secondary Toolbar item is hidden by design .
Check the threads :
How to change icon of Secondary Toolbaritem Xamarin Forms.
https://forums.xamarin.com/discussion/47989/icon-for-toolbaritem-with-order-secondary.
I create the workaround that mentioned in the links, it works fine .
Xaml
<ContentPage.ToolbarItems>
<ToolbarItem Order="Primary" Icon="dots.png" Priority="1" Clicked="ToolbarItem_Clicked" />
</ContentPage.ToolbarItems>
<RelativeLayout>
<ListView x:Name="SecondaryToolbarListView"
VerticalOptions="Start"
HorizontalOptions="Start"
WidthRequest="150" IsVisible="False"
ItemTapped="SecondaryToolbarListView_ItemTapped"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1, Constant=-160}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Spacing="10" Padding="5,5,5,5">
<Image HeightRequest="30" HorizontalOptions="Start" VerticalOptions="Center" Source="{Binding ImagePath}" />
<Label FontSize="15" VerticalOptions="Center" HorizontalOptions="Start" Text="{Binding MenuText}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</RelativeLayout>
Code behind
public class ToolbarItemModel
{
public string ImagePath { get; set; }
public string MenuText { get; set; }
}
public Page2()
{
InitializeComponent();
var items = new List<ToolbarItemModel>
{
new ToolbarItemModel {ImagePath = "dog.png", MenuText = "First Item"},
new ToolbarItemModel {ImagePath = "dog.png", MenuText = "Second Item"}
};
SecondaryToolbarListView.ItemsSource = items;
}
private void ToolbarItem_Clicked(object sender, EventArgs e)
{
SecondaryToolbarListView.IsVisible = !SecondaryToolbarListView.IsVisible;
}
private void SecondaryToolbarListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
}
The Images aren't appearing because you have incorrectly added icon_share.png and icon_delete.png to your project.
Here is Microsoft's recommendations on how to add images to your Xamarin.Forms project:
Image files can be added to each application project and referenced from Xamarin.Forms shared code. This method of distributing images is required when images are platform-specific, such as when using different resolutions on different platforms, or slightly different designs.
To use a single image across all apps, the same filename must be used on every platform, and it should be a valid Android resource name (i.e. only lowercase letters, numerals, the underscore, and the period are allowed).
iOS - The preferred way to manage and support images since iOS 9 is to use Asset Catalog Image Sets, which should contain all of the versions of an image that are necessary to support various devices and scale factors for an application. For more information, see Adding Images to an Asset Catalog Image Set.
Android - Place images in the Resources/drawable directory with Build Action: AndroidResource. High- and low-DPI versions of an image can also be supplied (in appropriately named Resources subdirectories such as drawable-ldpi, drawable-hdpi, and drawable-xhdpi).
Universal Windows Platform (UWP) - By default, images should be placed in the application's root directory with Build Action: Content. Alternatively, images can be placed in a different directory which is then specified with a platform-specific. For more information, see Default image directory on Windows.
Recommendations
Permanently Remove Icon; Icon was deprecated in favor of IconImageSource
Temporarily remove IconImageSource, replacing it with Text="Share" and Text="Delete":
This will confirm that ContentPage.ToolbarItems is working properly and that you have incorrectly added your png images to the Xamarin.Forms project
<ContentPage.ToolbarItems>
<ToolbarItem Name="Share" Order="Secondary" Text="Share" />
<ToolbarItem Name="Delete" Order="Secondary" Text="Delete" />
</ContentPage.ToolbarItems>

How to Delete / Show a StackLayout through the code behind of my View with MVVM

You want to hide a StackLayout depending on the value of a property that is evaluated in the constructor, but when hiding it xamarin leaves the blank and does not upload the lower elements upwards, so I will remove the element through code behind (I'm using MVVM)
But I do not know how to structure my code so that I can evaluate whether or not I eliminate the StackLayout when loading the Vista
In my view I occupy X: Name to identify the element that I want to eliminate or show, after evaluating the condition.
MyView.XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BindingContext="{Binding Main, Source={StaticResource Locator}}"
x:Class="AppValora.Views.Sisquim.VerSisquimView">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start">
<Image
HorizontalOptions="Center"
Source="{Binding ImageRombo}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
<Image
HorizontalOptions="Center"
Source="cuadro_nch"
HeightRequest="160"
WidthRequest="160">
</Image>
</StackLayout>
// STACKLAYOUT YOU WANT TO ELIMINATE
<StackLayout
x:Name="StackIsVisible">
<Image
Source="{Binding ImageRomboDos}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
</StackLayout>
</ContentPage>
In my ViewModel, I receive the parameter that I then evaluate in a conditional
MyViewModel.CS:
public VerSisquimViewModel(SqsHelper sqsHelper)
{
if (sqsHelper.RSEC == null)
{
IsVisibleLabelRomboImagenDos = false;
}
}
What magic can I do in my Code Behind so that when the condition is met, eliminate the StackLayout and disappear that blank space?
currently I have....
MyView.cs (CODE BEHIND):
public partial class MyView : ContentPage
{
StackLayout hiddenStackLayout;
public VerSisquimView ()
{
NavigationPage.SetBackButtonTitle(this, "");
StackIsVisible.Children.RemoveAt(1);
InitializeComponent();
}
}
how can I from the code behind change the value of the property when I start this page?
Is it a bad practice to use code behind with the MVVM pattern?
How can i fix this? any help for me?
Is it a bad practice to use code behind with the MVVM pattern?
If the code is view related, than it's necessary. Sometimes you just can't avoid code in the code-behind. A Rule to keep in mind, typically when you start working with the view, managing things can get to be quite cumbersome. If you find a way to leverage the platform, in this case Xaml, let it do the work for you.
the thing about visibility, the element is rendered on the screen. The user just can't see it. This is why the space is being taken up. Sometimes visibility will work, other times not so much.
In this situation, you can avoid code in code-behind and stick to your VM.
I would suggest using a grid and use a converter to hide a grid row. When I say hide the row, I mean by setting a row's height to 0. So it's rendered but we are going to collapse it. I only added two rows, you can add more to accommodate more content as you see fit.
Edit: added sample namespace. If you are using Visual Studio, there should be intellisense. You have to add the local namespace, so the xaml engine can find the converter class.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converter="clr-namespace:DataBindingDemos" <-- set the appropriate value
BindingContext="{Binding Main, Source={StaticResource Locator}}"
x:Class="AppValora.Views.Sisquim.VerSisquimView">
<ContentPage.Resources>
<converter:BoolToGridRowVisibilityConverter key="BoolToGridRowVisibilityConverter">
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="{Binding IsStackVisible, Converter={StaticResource BoolToGridRowVisibilityConverter}}" />
</Grid.RowDefinitions>
<StackLayout
Grid.Row="0"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start">
<Image
HorizontalOptions="Center"
Source="{Binding ImageRombo}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
<Image
HorizontalOptions="Center"
Source="cuadro_nch"
HeightRequest="160"
WidthRequest="160">
</Image>
</StackLayout>
<!-- STACKLAYOUT YOU WANT TO ELIMINATE -->
<StackLayout Grid.Row="1"
x:Name="StackIsVisible">
<Image
Source="{Binding ImageRomboDos}"
HeightRequest="160"
WidthRequest="160"
IsVisible="{Binding IsVisibleImagenRombo}">
</Image>
</StackLayout>
</Grid>
</ContentPage>
Add a converter
public class BoolToGridRowVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? new GridLength(1, GridUnitType.Auto) : new GridLength(0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException("Only one way bindings are supported with this converter");
}}
}
For more information, see a post on Xamarin forums
You can put the IsVisible="{Binding IsVisibleImagenRombo}" to the StackIsVisible stacklayout, so that the entire space will be erased.

User Control With Image To bind in windows phone

I want to make a user control that contains Image control and I want to bind its source with a url of image. How to do this in the user control XAMl and CS code and how to use this user control and bind its dependency property ?
You could have the Image control like this, which you could bind the source to it:
<Image Width="75" Height="75" Source="{Binding thumbUrl}" Stretch="Fill"/>
For more you could refer these:
Image databinding XAML, Silverlight, C#, Windows Phone 7.1
http://www.geekchamp.com/tips/data-binding-images-in-windows-phone
Hope it helps!
You can create a user control by,
(i)Right click the project tile in Solution Explorer and then select Add->New Item
(ii)Select Windows Phone User Control from the pop up windows, set the name that you want to use
(iii)Add the following code inside the XAML part of the user control
<StackPanel x:Name="LayoutRoot" >
<TextBlock Text="My User Control" FontSize="34"/>
<Image x:Name="Image1" Source="{Binding ImageUrl}" />
</StackPanel>
Define a property in your Model,
public Uri ImageUrl { get; set; }
and bind it to your Image
Uri uri = new Uri("http://Abundantcode.com/image.jpg", UriKind.Absolute)
Image1.Source = new BitmapImage(uri);
Now you can use UserControl anywhere you want,
<local:MyUserControl x:Name="myUserControl" />

Binding an Image in WPF MVVM

I am having some trouble binding in Image to my viewmodel. I finally got rid of the XamlParseException, but the image does not come up. I even hard coded the image in the ViewModel. Can someone see what I am doing wrong?
View:
<Image HorizontalAlignment="Left" Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom" Grid.Row="8" Width="200" Grid.ColumnSpan="2" >
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="{Binding Path=DisplayedImage, Mode=TwoWay}" />
</Image.Source>
ViewModel:
string _DisplayedImagePath = #"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg";//string.Empty;
int _DisplayedImageIndex;
BitmapImage _DisplayedImage = null;
public BitmapImage DisplayedImage
{
get
{
_DisplayedImage = new BitmapImage();
if (!string.IsNullOrEmpty(_DisplayedImagePath))
{
_Rail1DisplayedImage.BeginInit();
_Rail1DisplayedImage.CacheOption = BitmapCacheOption.OnLoad;
_Rail1DisplayedImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_Rail1DisplayedImage.UriSource = new Uri(_DisplayedImagePath);
_Rail1DisplayedImage.DecodePixelWidth = 200;
_Rail1DisplayedImage.EndInit();
}
return _Rail1DisplayedImage;
}
set
{
_Rail1DisplayedImage = value;
OnPropertyChanged("DisplayedImage");
}
}
Displaying an Image in WPF is much easier than that. Try this:
<Image Source="{Binding DisplayedImagePath}" HorizontalAlignment="Left"
Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom"
Grid.Row="8" Width="200" Grid.ColumnSpan="2" />
And the property can just be a string:
public string DisplayedImage
{
get { return #"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"; }
}
Although you really should add your images to a folder named Images in the root of your project and set their Build Action to Resource in the Properties Window in Visual Studio... you could then access them using this format:
public string DisplayedImage
{
get { return "/AssemblyName;component/Images/ImageName.jpg"; }
}
UPDATE >>>
As a final tip... if you ever have a problem with a control not working as expected, simply type 'WPF', the name of that control and then the word 'class' into a search engine. In this case, you would have typed 'WPF Image Class'. The top result will always be MSDN and if you click on the link, you'll find out all about that control and most pages have code examples as well.
UPDATE 2 >>>
If you followed the examples from the link to MSDN and it's not working, then your problem is not the Image control. Using the string property that I suggested, try this:
<StackPanel>
<Image Source="{Binding DisplayedImagePath}" />
<TextBlock Text="{Binding DisplayedImagePath}" />
</StackPanel>
If you can't see the file path in the TextBlock, then you probably haven't set your DataContext to the instance of your view model. If you can see the text, then the problem is with your file path.
UPDATE 3 >>>
In .NET 4, the above Image.Source values would work. However, Microsoft made some horrible changes in .NET 4.5 that broke many different things and so in .NET 4.5, you'd need to use the full pack path like this:
<Image Source="pack://application:,,,/AssemblyName;component/Images/image_to_use.png">
For further information on pack URIs, please see the Pack URIs in WPF page on Microsoft Docs.
If you have a process that already generates and returns an Image type, you can alter the bind and not have to modify any additional image creation code.
Refer to the ".Source" of the image in the binding statement.
XAML
<Image Name="imgOpenClose" Source="{Binding ImageOpenClose.Source}"/>
View Model Field
private Image _imageOpenClose;
public Image ImageOpenClose
{
get
{
return _imageOpenClose;
}
set
{
_imageOpenClose = value;
OnPropertyChanged();
}
}
#Sheridan thx.. if I try your example with "DisplayedImagePath" on both sides, it works with absolute path as you show.
As for the relative paths, this is how I always connect relative paths, I first include the subdirectory (!) and the image file in my project.. then I use ~ character to denote the bin-path..
public string DisplayedImagePath
{
get { return #"~\..\images\osc.png"; }
}
This was tested, see below my Solution Explorer in VS2015..
)
Note: if you want a Click event, use the Button tag around the image,
<Button Click="image_Click" Width="128" Height="128" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left">
<Image x:Name="image" Source="{Binding DisplayedImagePath}" Margin="0,0,0,0" />
</Button>

How to set XamDataTree Icon to Bitmap instead of file name

I've set the XamDataTree image, but I don't want to copy the image folder to my debug folder every time. Instead I want to add the image to my project resources and use it from there. Currently no image is shown because it expects a path to an image where I give it an actual bitmap. The Icon property in the TreeNode is set in another part of the code.
This is my Xaml code:
<ig:XamDataTree
Grid.Row="1"
Name="MyTree"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding ComparedContents}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
>
<ig:XamDataTree.CheckBoxSettings>
<ig:CheckBoxSettings CheckBoxVisibility="Visible" />
</ig:XamDataTree.CheckBoxSettings>
<ig:XamDataTree.CollapsedIconTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}"/>
</DataTemplate>
</ig:XamDataTree.CollapsedIconTemplate>
<ig:XamDataTree.ExpandedIconTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}"/>
</DataTemplate>
</ig:XamDataTree.ExpandedIconTemplate>
<ig:XamDataTree.GlobalNodeLayouts>
<ig:NodeLayout
Key="Children"
DisplayMemberPath="Text"
TargetTypeName="Model.TreeNode"
>
</ig:NodeLayout>
</ig:XamDataTree.GlobalNodeLayouts>
</ig:XamDataTree>
This is my model, each Property has a private store for the value and fires an event if it changes.
public class TreeNode : INotifyPropertyChanged
{
public Label Text;
public System.Drawing.Image Icon;
public ObservableCollection<TreeNode> Children;
}
Assuming you embedded the image into your application, you can use a pack uri to load the image into the node template. Instead of using an Image type on your Icon property you should use Uri and set it equal to something like this:
Icon = new Uri("pack://application:,,,/Resources/Images/icon.png");
You need to modify the binding in your templates a bit because the DataContext of this template is going to be a XamDataTreeNodeDataContext. This object has a Data property which will be your TreeNode object. Your binding should be updated to:
<Image Source="{Binding Path=Data.Icon}"/>

Categories

Resources