Xamarin Form: Custom Extension not found - xamarin

I created an ImageResourceExtension class in a under Common Assembly name. I checked the name under the Reference in Property window setting. Namespace for this extension is Extension.Common.
The xaml of the working project which using this Common Assembly have a declaration as:
xmlns:common="clr-namespace:Extension.Common;assembly:Common"
The element was written as :
<common:BooleanToObjectConverter x:Key="boolToStyleImage"
x:TypeArguments="Style">
<common:BooleanToObjectConverter.FalseObject>
<Style TargetType="Image">
<Setter Property="HeightRequest" Value="20" />
<Setter Property="Source" Value="{common:ImageResource Common.Images.error.png}" />
</Style>
</common:BooleanToObjectConverter.FalseObject>
The images was stored in a Common project folder inside Images directory
I named the ImageResource file as ImageResourceExtension.cs and tried ImageResource.cs but none of it work. It just give me an exception saying:
MarkupExtension not found for common:ImageResource
I have no idea what go wrong. Have follow all the steps for a blog.
The project that I placed those xaml stuff are in a shared project. Don't know will it make any difference

I hope I understand good your question !
look at this code:
[ContentProperty("Source")]
public class ImageSourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
{
return null;
}
// Do your translation lookup here, using whatever method you require
var imageSource = ImageSource.FromResource("Project.Images." + Source);
return imageSource;
}
}
Now, if you want to use an image as you did in your xaml, something like that should work:
<Image Source="{extension:ImageSource LogoProject.png}"/>
Note 1: I only put the name of the image because in the extension, the path is put automatically ;)
Note 2: You have to put the assembly/namespace as I do below:
xmlns:extension="clr-namespace:Project.Sources.Extensions;assembly=Project"
Also, you're image has to be an EmbeddedResource, do not forget about it. For the path, it's Project.Path.Image.png and not assembly as well ;)
I hope I understood your question and I could help you :)

Related

is there any way to set Source for Image From .standard Class Library in UWP

I have create Xamarin Native App only create UI Part platform specfic and shared code(Model,ViewModel) using .net stadard class Library.
In UWP Project I set Source Path Like this
Source="pack://application:,,,/MyClassLibraryName;Component/Assets/AppLogo.png"
It does not work for me!
I have create Xamarin Native App only create UI Part platform specfic and shared code(Model,ViewModel) using .net stadard class Library
For this scenario, you could refer this document that make ImageResourceExtension to load the Embedded image from .net stadard class Library.
We need add the following code to .net stadard class Library.
[Preserve(AllMembers = true)]
[ContentProperty(nameof(Source))]
public class ImageExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
return null;
// Do your translation lookup here, using whatever method you require
var imageSource = ImageSource.FromResource(Source, typeof(ImageExtension).GetTypeInfo().Assembly);
return imageSource;
}
}
Then add image file to .net standard class library and edit the Build Action to Embedded
Usage
ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mySource="clr-namespace:ImageLib;assembly=ImageLib"
x:Class="WorkingWithImages.EmbeddedImagesXaml">
<StackLayout Margin="20,35,20,20">
<Image Source="{mySource:Image ImageLib.logo.jpg}" />
</StackLayout>
/ContentPage>
Please note: Image path is classlibname.imagename.jpg
Update
You could use uwp uri scheme to add the image path to imgage control, for example
<ImageBrush ImageSource="ms-appx:///Image/AppLogoicon.png" Stretch="UniformToFill" x:Name="Image" />

Insert Html file content in xamarin forms

I have one Html file. That html file contains only some div. and i have applied some styles to that all div like margin, color and font-family. Now i want to make a page in my xamarin form app(both in ios and android) and want to add that html file's whole contain in my page.
I have tried by using web view control of xamarin forms. But my html file's content is too long, and because of that, xamarin code is going too long too as we have to applied html as a string to web view control. so i don't want to use that way.
So please give me brief explanation or solution to add html file in xamarin forms.
Hope for better solution.
Thanks in advance.
Not 100% sure what do you mean by "xamarin code is going to long too".
But you can make HtmlWebViewSource object in your ViewModel or in a code-behind, depending what approach you are using and later on you can set or bind WebViews's Source property to it.
In order to set it from code-behind you can do it like this:
var htmlSource = new HtmlWebViewSource();
htmlSource.Html = #"<html><body><h1>Xamarin is awesome</h1></body></html>";
yourWebView.Source = htmlSource;
On the other hand, if you are using MVVM and whole View-ViewModel concept you just need to have a property in your ViewModel of type HtmlWebViewSource and do the simple binding in your View.
Let's say you have the property of type HtmlWebViewSource named HtmlSource, you can set its value to your HTML content like we did in the previous example and than bind to it from WebView control, that should look something like this:
<WebView x:Name="yourWebView" Source="{Binding HtmlSource}" WidthRequest="1000" HeightRequest="1000" />
Hope this was helpful for you, wishing you lots of luck with coding!
If you want to load local html in your contentpage, I suggest you can use DependencyService to get html url from Android Assets file, I create simple in android that you can take a look.
Firstly, creating html in Android--Assets file, name as TestWebPage.html.
Then Creating Interface in Form, IBaseUrl.
public interface IBaseUrl
{
string GetUrl();
}
Then implementing this interface in Android platform:
public class LocalFiles : IBaseUrl
{
public string GetUrl()
{
return "file:///android_asset/";
}
}
ContentPage code:
<StackLayout>
<!-- Place new controls here -->
<WebView
x:Name="webviewjava"
HeightRequest="300"
WidthRequest="300" />
</StackLayout>
public MainPage()
{
InitializeComponent();
var urlSource = new UrlWebViewSource();
string baseUrl = DependencyService.Get<IBaseUrl>().GetUrl();
string filePathUrl = Path.Combine(baseUrl, "TestWebPage.html");
urlSource.Url = filePathUrl;
webviewjava.Source = urlSource;
}
Here is the sample at github, you can take a look:
https://github.com/CherryBu/htmlapp

How to set an image from Embedded resource using XAML in Xamarin.Forms

When setting an image source in code and pointing towards an embedded image in a specific folder in the PCL project ('Images' in this instance) I would do this:
backgroundImg.Source = ImageSource.FromResource("Myapp.Images." + imageName + ".jpg");
Is there a way to do this in XAML?
#Code Pope is correct in his answer, but you also need to add an "ImageResourceExtension" as noted in the comments by #Gerald Versluis.
To do that just create a new file (class) "ImageResourceExtension.cs" like this:
using System;
using System.Reflection;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ImageResourceExtension
{
[ContentProperty (nameof(Source))]
class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
{
return null;
}
var imageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
return imageSource;
}
}
}
Then add xmlns:local="clr-namespace:ImageResourceExtension" to your xaml file like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ImageResourceExtension"
...
Now you can access an embedded resource using xaml code like this:
<Image Source="{local:ImageResource MyProject.Resources.Images.Logo.png}" />
Use the following code:
<Image Source="{local:ImageResource YourMobileAppName.YouImageName.jpg}" />
For more info, read here
I managed to get this working by adding the ImageSource as an object in my View Model
public object ImageSource { get; set; }
Then populating the View Model as follows:
ImageSource = Xamarin.Forms.ImageSource.FromResource("ProjectName.Resources.Images.Image1.png", typeof(WalkthroughViewModel).GetTypeInfo().Assembly),
In the XAML, I simply referenced it as I would any other binding.
<Image Source="{Binding ImageSource}"/>
I am aware that the question doesn't necessarily use/require model-binding as you would with MVVM but I stumbled upon the answer provided above which helped me figure out the MVVM approach for anyone else who finds it useful. My particular use-case was for a CarouselView where I figured an embedded set of images would be useful.
you can set image from xaml like <Image Source="imageName" Aspect="AspectFit" />
Make sure your image available in iOS Resources and in Android Resources -> drawable

Xamarin Forms Display image from Embedded resource using XAML

I'm trying to display and embedded image in a shared project resource (as explained here on microsoft documentation).
I created the ImageResourceExtension, the project compiles, but I get the following error when I start the project :
Could not load type 'Xamarin.Forms.Xaml.IReferenceProvider' from
assembly 'Xamarin.Forms.Core, Version=2.0.0.0
Here's my code :
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<StackLayout>
<Image x:Name="imgTest" Source="{local:ImageResource img.jpg}" />
</StackLayout>
</ContentPage>
EmbeddedImage.cs
namespace App1
{
[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null)
return null;
// Do your translation lookup here, using whatever method you require
var imageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
return imageSource;
}
}
}
You can try this, it works for me
xyz.xaml.cs
imgName.Source = ImageSource.FromResource("ProjectName.Images.backicon.png");
xyz.xaml
<Image x:Name="imgName" />
Hope this code helps you!!
Not knowing if the answer is still valid for you, but I usually have an Assets folder outside my solution which contains Android specific folders (drawables), iOS specific folders (Resource with #2x and #3x) and a Common folder for shared images.
In my solution I add these files as a link in the folders they should be associated with. On Android in the Resources/Drawable and iOS in the Resource. In this case Common files can be shared across both platforms without physically copying them.
As a bonus, updates to these Assets can be overwritten in the folder outside my solution and will be used within my solution without any additional action to be taken.
Replace:
<Image x:Name="imgTest" Source="{local:ImageResource img.jpg}" />
With:
<Image x:Name="imgTest" Source="{local:ImageResource 'Project.Folder.img.jpg'}" />
And Replace:
var imageSource = ImageSource.FromResource(Source, typeof(...));
With:
var imageSource = ImageSource.FromResource(Source);
If you add the Image to your Android drawable folder, or to the iOS Resource folder, you don't need any extension. You can simply do:
<Image x:Name="imgTest" Source="img.jpg" />

Xamarin: add image to my button from PCL (not from Resources)

I'm working on a Xamarin.Forms project utilizing PCL (not the shared project).
I have a few images in my Resources folders in both Android and iOS project.
This works and the icons show in buttons as they're supposed to:
<Button Image="speaker.png" Grid.Row="0" Grid.Column="0" />
I also have a folder in my PCL project with some images: images/icons/speaker.png
I've tried this:
<Button Image="{local:EmbeddedImage TestThree.images.icons.speaker.png}" />
...but that didn't work...
I would like those buttons to show images from my images folder in my PCL project.
So my question would be...
<Button WHAT GOES HERE? Grid.Row="0" Grid.Column="0" />
When Button.Image wants FileImageStream, I give it to him. But as images in the project I still use embedded resources PNG files in PCL (or .NET standard 2.0) library (project).
For example the PCL project name is "MyProject" and I have an image placed in its subfolder "Images\Icons\ok.png". Then the resource name (e.g. for ImageSource.FromResource) is "MyProject.Images.Icons.ok.png".
This method copies embedded resource file into the file in application local storage (only first time).
public static async Task<string> CopyIcon(string fileName)
{
if (String.IsNullOrEmpty(fileName)) return "";
try
{
// Create (or open if already exists) subfolder "icons" in application local storage
var fld = await FileSystem.Current.LocalStorage.CreateFolderAsync("icons", CreationCollisionOption.OpenIfExists);
if (fld == null) return ""; // Failed to create folder
// Check if the file has not been copied earlier
if (await fld.CheckExistsAsync(fileName) == ExistenceCheckResult.FileExists)
return (await fld.GetFileAsync(fileName))?.Path; // Image copy already exists
// Source assembly and embedded resource path
string imageSrcPath = $"MyProject.Images.Icons.{fileName}"; // Full resource name
var assembly = typeof(FileUtils).GetTypeInfo().Assembly;
// Copy image from resources to the file in application local storage
var file = await fld.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
using (var target = await file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite))
using (Stream source = assembly.GetManifestResourceStream(imageSrcPath))
await source.CopyToAsync(target); // Copy file stream
return file.Path; // Result is the path to the new file
}
catch
{
return ""; // No image displayed when error
}
}
When I have a regular file, I can use it for the FileImageStream (Button.Image).
The first option is use it from the code.
public partial class MainPage : ContentPage
{
protected async override void OnAppearing()
{
base.OnAppearing();
btnOk.Image = await FileUtils.CopyIcon("ok.png");
}
}
Also I can use it in the XAML, but I must create an implementation of IMarkupExtension interface.
[ContentProperty("Source")]
public class ImageFileEx : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
return Task.Run(async () => await FileUtils.CopyIcon(Source)).Result;
}
}
Now I can assign the image direct in the XAML.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyProject"
x:Class="MyProject.MainPage"
xmlns:lcl="clr-namespace:MyProject;assembly=MyProject">
<Grid VerticalOptions="Fill" HorizontalOptions="Fill">
<Button Image="{lcl:ImageFileEx Source='ok.png'}" Text="OK" />
</Grid>
</ContentPage>
For this solution the NuGet PCLStorage is needed.
The reason that does not work is because the properties are bound to different types.
Button's Image property takes a "FileImageSource" - Github
Image's Source property takes a "ImageSource" - Github
From the local:EmbeddedImage im guessing you were using the extension from Xamarin forms image docs
That would not work because it loads a "StreamImageSource" instead of "FileImageSource".
In practice you should not do this as it would not load from different dimension images(#2x, xhdpi etc) and would give bad quality images and not support multiple resolutions.
You could use a view container(Stack layout etc) with a TapGestureRecognizer and an image centered inside it or create a custom renderer which really is more effort than its worth. None of these still would still obviously not handle multiple images though.
The correct solution would be to generate the correct size images from the base(Which I would assume would be MDPI Android or 1X for iOS) and put them in the correct folders and reference them in your working Button example.

Resources