Changing/Updating Image in XAML - xamarin

I'm having an issue updating my Images in my Xamarin UWP app. First, I'd like to say I have seen multiple other threads on this issue, but none have been able to solve my predicament and a lot are very outdated.
Here is my scenario: I have three images I am using, named green.png, red.png, and gray.png. I am displaying one Image in my Xamarin app, and depending on a specific float called in my associated .cs file, I want to change the Image to another color. So, for example, if the float goes below 15, I want the Image to be the Red one.
Here is how I am currently displaying my Images without code for changing them, i.e. this code works fine and my Images appear in the app:
<Image Source="{pages:ImageResource BLE.Client.Pages.red.png}" Opacity="0.6"/>
They are currently stored in the same directory as the XAML files themselves. I know that on Android there is a Resources folder, but I don't see any equivalent for UWP, so I am loading my Images this way.
One way I attempted to do this based on another post I saw here is this:
<Image Source="{Binding HeadColor, StringFormat='pages:ImageResource BLE.Client.Pages.\{0\}.png', Mode=TwoWay}" Opacity="0.6"/>
The way this is supposed to function is depending on the value of my float, I used the string HeadColor in my .cs file and do an OnPropertyChanged on it. It always contains either the string "green", "red", or "gray", and with this method it should slot itself into the Image location string. However, this does not work.
For reference, here is how I update my HeadColor string in my .cs file:
private string _HeadColor;
public string HeadColor {get => _HeadColor; set {_HeadColor = value; OnPropertyChanged("HeadColor");}}
...
if (SensorAvgValue > 15) {_HeadColor = "green";}
else {_HeadColor = "red";}
RaisePropertyChanged(() => HeadColor);
I have also tried using an IValueConverter, but that does not work either.
So, in summary, my question is how to best go about dynamically changing which Image I'd like to use. They are all the same dimensions and in the same directory, the only difference being their names "green.png", "red.png", and "gray.png". Is there a better way to call/load the Images?
Thanks!

this works for me on iOS - I don't have a UWP env to test with, but it should work the same. I have two images "reddot.png" and "greendot.png" in my iOS Resources
<StackLayout Padding="20,50,20,50">
<Image Source="{Binding HeadColor, StringFormat='\{0\}dot.png'}" Opacity="0.6"/>
<Button Clicked="ChangeColor" Text="Click!!" />
</StackLayout>
code-behind
public partial class MainPage : ContentPage, INotifyPropertyChanged
{
private string headColor = "red";
public string HeadColor
{
get
{
return headColor;
}
set
{
headColor = value;
OnPropertyChanged();
}
}
public MainPage()
{
InitializeComponent();
this.BindingContext = this;
}
protected void ChangeColor(object sender, EventArgs args)
{
if (HeadColor == "red")
{
HeadColor = "green";
}
else
{
HeadColor = "red";
}
}
}

Related

After installing FFImageLoading images don't show at all

My Xamarin Forms 5 app will allow users to upload their own images which can be large. I noticed that large images were taking a long time to show so I installed FFImageLoading and followed the instructions on their Github page at https://github.com/luberda-molinet/FFImageLoading/wiki/Xamarin.Forms-API.
Specifically, I installed the following packages:
Xamarin.FFImageLoading Version="2.4.11.982"
Xamarin.FFImageLoading.Forms Version="2.4.11.982"
Xamarin.FFImageLoading.Svg.Forms Version="2.4.11.982"
Xamarin.FFImageLoading.Transformations Version="2.4.11.982"
I also initialized it as follows:
Under Android, in OnCreate method of MainActivity.cs, I added FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer:true); AND FFImageLoading.Forms.Platform.CachedImageRenderer.InitImageViewHandler();
Under iOS, in FinishedLaunching() method of AppDelegate.cs, I added FFImageLoading.Forms.Platform.CachedImageRenderer.Init(); AND FFImageLoading.Forms.Platform.CachedImageRenderer.InitImageSourceHandler();
I first tried it without changing anything in my XAML files, meaning I used the regular Image control and images would NOT show at all.
I then tried the following and I see NOTHING at all:
...
xmlns:ffil="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
...
<ffil:CachedImage
Source="{Binding FileUrl}"
DownsampleWidth="150"
DownsampleToViewSize="True"/>
IMPORTANT:
I also want to mention that the images are displayed within CollectionView controls AND in all cases, their source is a URL and NOT a local path.
Any idea what maybe the issue here and how to fix it?
As I'm aware FFImageLoading is not maintained anymore. A lot of apps are still using the package but keep in mind that reported open issues will most likely not be fixed. It is sad because this is one of the most popular packages for Xamarin Forms, but it looks like we will have to start looking for alternatives.
Good luck with this.
I checked your steps that you followed the instructions.Obviously,your steps are correct and I manage to display the image{using URL} with CollectionView as you said,hope it can give you some insights.
Model:
MyModel.cs
public class MyModel
{
public int id { get; set; }
public string FileUrl { get; set; }
}
View:
MainPage.xaml
<CollectionView ItemsSource="{Binding MyModels}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView Padding="0">
<ffil:CachedImage
Source="{Binding FileUrl}"
DownsampleWidth="150"
DownsampleToViewSize="True"/>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Bind the ViewModel in backend:
BindingContext = new MainPageViewModel();
ViewModel:
MainPageViewModel.cs
public class MainPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<MyModel> myModels;
public ObservableCollection<MyModel> MyModels
{
get { return myModels; }
set { myModels = value; }
}
public MainPageViewModel()
{
MyModels = new ObservableCollection<MyModel>
{
new MyModel{id = 1, FileUrl = "http://loremflickr.com/600/600/nature?filename=simple.jpg"},
new MyModel{id = 2, FileUrl ="http://loremflickr.com/600/600/nature?filename=simple.jpg"},
new MyModel{id = 3, FileUrl = "http://loremflickr.com/600/600/nature?filename=simple.jpg"},
new MyModel{id = 4, FileUrl ="http://loremflickr.com/600/600/nature?filename=simple.jpg"},
new MyModel{id = 5, FileUrl = "http://loremflickr.com/600/600/nature?filename=simple.jpg"},
new MyModel{id = 6, FileUrl ="http://loremflickr.com/600/600/nature?filename=simple.jpg"}
};
}
}
Update:
In Android, it works well.However,in iOS there's already a reported issue:
github.com/luberda-molinet/FFImageLoading/issues/1498

developing a picker that pops out from the selected frame downward in xamarin forms

I have a design i'm trying to implement. Although I've ben working with Rg.plugin for a while trying out different animations and entry behaviour but it's always covering the whole screen.
However, the current design I'm working with is different.
here is the image
Please does anyone have an idea how I can achieve this using xamarin forms please.
Any help will be appreciated.
Note, I already have the design in place using pancakeView and Rg.plugin to pop it out on click. However, the positioning is what I haven't been able to achieve. though I've not written any code for it yet cos I prefer to do my research right.
Please I need anyone to point me to the right path or how to achieve this.
thanks in advance
According to your screenshot, you can do custom control using entry and ListView to get it, there is also one custom control that you can take a look:
Installing Xamarin.Forms.EntryAutoComplete
Uisng this custom control like:
<ContentPage
x:Class="demo3.listviewsample.Page36"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:customControl="clr-namespace:EntryAutoComplete;assembly=EntryAutoComplete">
<ContentPage.Content>
<StackLayout>
<customControl:EntryAutoComplete
ItemsSource="{Binding Countries}"
MaximumVisibleElements="5"
Placeholder="Enter country..."
SearchMode="{Binding SearchMode}"
SearchText="{Binding SearchCountry}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
public class dialogvidemodel:ViewModelBase
{
private string _searchCountry = string.Empty;
private SearchMode _searchMode = SearchMode.Contains;
public string SearchCountry
{
get => _searchCountry;
set
{
_searchCountry = value;
RaisePropertyChanged("SearchCountry");
}
}
public List<string> Countries { get; } = new List<string>
{
"African Union",
"Andorra",
"Armenia",
"Austria",
"Togo",
"Turkey",
"Ukraine",
"USA",
"Wales"
};
public SearchMode SearchMode
{
get => _searchMode;
set
{
_searchMode = value;
RaisePropertyChanged("SearchMode");
}
}
}
More detailed info, please take a look:
https://github.com/krzysztofstepnikowski/Xamarin.Forms.EntryAutoComplete

What is the property in control to be set to get the value from AppResult.Text in Xamarin.UITest?

I am trying to create custom control in Xamarin.Forms which has the unique id for automation. So, i have set the android renderer's contentDescription property. So, i can get the AppResult.Label property to identify the control. But, my requirements is that how to get the control's text property? What property i have to set in control level with the corresponding text to get it in AppResult.Text property.
[Test]
[Description("SampleTest")]
public void WelcomeTextIsDisplayed()
{
App.Repl();
AppResult[] results = App.WaitForElement("myControl");
Assert.IsTrue(results[0].Text == "My Control Text", results[0].Text + "\n" + results[0].Description + "\n" + results[0].Id + "\n" + results[0].Label);
}
For more information, I have prepared the simple example to explain better about my case. Here, i have derived my custom control from Grid and i introduced the Text property. When i try to view the element using Repl() method, it does not show the Text property but it shows the text properties for Label & Entry controls.
<StackLayout >
<Label Text="Hello, Custom Renderer!" />
<local:MyEntry Text="In Shared Code" AutomationId="myEntry" />
<local1:CustomView Text="Sample" BackgroundColor="Red" HeightRequest="500" AutomationId="customControl" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/>
</StackLayout>
public class CustomView : Grid
{
public CustomView()
{
}
public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(string),string.Empty);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
Result while calling App.Repl() ,
I'm not sure how different Xamarin.Forms are to Xamarin.Android (which is mostly what my experience is in.)
What happens if you try
app.Query(c => c.Id("NoResourceEntry-2").Property("Text")).SingleOrDefault();
or some variation of the above? Can you then do something with this? I Hope this helps or points you in the right direction.
Try to use with index position like this:
app.Query(c=>c.Id("NoResourceEntry-2"))[0].Text
similarly you can use class for same:
app.Query(c=>c.Class("LabelRenderer"))[0].Text
Query for Class("LabelRenderer") gave 2 results. So in above example, you can see it gave you 2 results but you have to use index for particular result.

how to display pdf in custom webview xamarin forms

i want to display pdf in webview from url using pdfjs, but i am getting empty view. here is my code
CustomWebView.cs
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create(propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(CustomWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
MainPage.xaml
<ContentPage.Content>
<local:CustomWebView Uri="http://veezo2007pkk.somee.com/api/DiagnosticDetail/RetrieveFile/1" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</ContentPage.Content>
App.Android
CustomWebViewRenderer.cs
public class CustomWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var customWebView = Element as CustomWebView;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.LoadUrl(string.Format("file:///android_asset/pdfjs/web/viewer.html?file={0}", string.Format("file:///android_asset/Content/{0}", WebUtility.UrlEncode(customWebView.Uri))));
}
}
}
it seems look fine, but i dont know why its not showing in webview....
I will assume two things here. One, you're not precious about PDF file being displayed in the WebView. Second you're OK with using 3rd party libraries.
I would suggest using SyncFusion PdfViewer. It's very easy to use and does everything you might want to do with PDFs - maybe not everything but a lot. If you're worried that you will need to pay a lot for these controls, fear not! SyncFusion has a free community license, which you can use (if you're not making more than a $1 mln USD and you don't have a larger team than 5 devs). You might want to have a look at this thread, talking about showing PDF from URL.

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