Cache is not getting cleared with FFimage - xamarin

I am trying to test FFImage Cached Image. Even after invalidating the cache, the image is not getting refreshed.
The old image is still coming.
<StackLayout Orientation="Horizontal">
<StackLayout>
<Label Text="1.jpg 15 min" FontSize="Title"/>
<ffimage:CachedImage HeightRequest="150" WidthRequest="150" Source="{Binding image1Source}"
CacheDuration="{Binding Duration}"/>
</StackLayout>
<StackLayout>
<Label Text="2.jpg 15 min" FontSize="Title"/>
<ffimage:CachedImage HeightRequest="150" WidthRequest="150" Source="{Binding image2Source}"
CacheDuration="{Binding Duration}"/>
</StackLayout>
</StackLayout>
Calling below to invalidate Cache:
FFImageLoading.ImageService.Instance.InvalidateDiskCacheAsync()
FFImageLoading.ImageService.Instance.InvalidateMemoryCache();
FFImageLoading.ImageService.Instance.InvalidateCacheAsync(FFImageLoading.Cache.CacheType.All)

Try to clear it on property setter
private string _imageSource{ get; set; }
public string image1Source
{
get{
return _imageSource;
};
set{
_imageSource= value;
await CachedImage.InvalidateCache(_imageSource, CacheType.All, true);
};
}

The issue was due to caching on the image url as well. the mobile cache was being clear but the server image was cached as well and hence we were getting the same image again which gave the impression of cache not being cleared.

Related

Change Image based on source name MAUI

Hi I'm new to coding in xamarin forms + MAUI with that said, my problem is that I'm trying to get a Image to change its source if the app loses/get connection to wifi.
I first tried to code like James Montemagno did for one of his video about databinding and i got it to work when I was typing in an entry. I then tried to do this automatically by using
"NetworkAccess accessType = Connectivity.Current.NetworkAccess;
    IEnumerable profiles = Connectivity.Current.ConnectionProfiles;'
and if this profile contains Wifi connection, i set a string called wifi to "wificonnected.png" if not wifi ="wifidisconnected.png".
This will not automatically change my Image source, it's just blank. Do you have any tips on what I should do, or do you have a more clever way?
I just want to build simple indicators.
 
ViewModel code:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DisplayV3.Pages;
namespace DisplayV3.ViewModels;
public partial class HomeViewModel : ObservableObject
{
NetworkAccess accessType = Connectivity.Current.NetworkAccess;
IEnumerable<ConnectionProfile> profiles = Connectivity.Current.ConnectionProfiles;
[NotifyPropertyChangedFor(nameof(HasWifi))]
[ObservableProperty]
string wifi;
public string HasWifi => $"{wifi}";
[RelayCommand]
async void CheckInternet()
{
if (profiles.Contains(ConnectionProfile.WiFi))
{
wifi = "wificonnected.png";
}
else
{
wifi = "wifidisconnected.png";
}
await App.Current.MainPage.DisplayAlert("Has", HasWifi, wifi);
//Console.WriteLine(HasWifi);
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
string firstName;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
string lastName;
public string FullName => $"{FirstName}{LastName}"; ```
Home Page/MainPage
``` <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodel="clr-namespace:DisplayV3.ViewModels"
x:DataType="viewmodel:HomeViewModel"
x:Class="DisplayV3.Pages.Home"
Title="Home">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Entry Placeholder="First name"
Text="{Binding FirstName}"/>
<Entry Placeholder="Last name"
Text="{Binding LastName}"/>
<Label
Text="{Binding FullName}"
HorizontalOptions="Center"/>
<Image
Source="{Binding HasWifi}"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="{Binding HasWifi}"
HorizontalOptions="Center"/>
<Button
Command="{Binding CheckInternetCommand}"
Text="Knapp"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ScrollView>
</ContentPage> ```
You can try to bind property Wifi to your Image View.
<Image
Source="{Binding Wifi}"
HeightRequest="200"
HorizontalOptions="Center" />
And you can change the value for property Wifi not wifi ,just as follows:
[NotifyPropertyChangedFor(nameof(HasWifi))]
[ObservableProperty]
string wifi;
public string HasWifi => $"{wifi}";
[RelayCommand]
async void CheckInternet()
{
if (profiles.Contains(ConnectionProfile.WiFi))
{
// replace wifi with `Wifi ` here
Wifi = "wificonnected.png";
}
else
{// replace wifi with `Wifi ` here
Wifi = "wifidisconnected.png";
}
await App.Current.MainPage.DisplayAlert("Has", HasWifi, wifi);
}
You are binding a non observable property so if that changes (HasWifi), it would never inpact on the ui, only on the view model.
[ObservableProperty]
string hasWifi => $"{Wifi}";

Navigate to specific page defined on model when Item is Tapped

I'm trying to make a custom home page where pages are listed on an Horizontal scroll view as "Services" so each one of them should navigate to a different Page.
I have a view like this:
<controls:HorizontalScrollView HeightRequest="160"
Orientation="Horizontal"
ItemsSource="{Binding OwnerServicesList}"
x:Name="OwnerServicesSlider"
ItemSelected="OwnerServicesSlider_ItemSelected">
<controls:HorizontalScrollView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="10,0,5,0" WidthRequest="100" HeightRequest="100">
<Image HorizontalOptions="Start" Source="{Binding ImgUrl}" WidthRequest="100" HeightRequest="100" />
<Label Style="{StaticResource BoldLabel}" HorizontalTextAlignment="Center" FontSize="13" LineBreakMode="TailTruncation" Text="{Binding Name}" TextColor="Black"/>
</StackLayout>
</ViewCell>
</DataTemplate>
Im using a custom made controller for a Horizontal Scroll view that works like a listview, every item on tap raises a ItemTappedEventArgs event.
Inside my model i´ve declared a public Page Page { get; set; } for each object in the scroll view.
What im trying to do is recover the tapped element and recover the Page stored in it so that I can Navigate to that specific page.
So far I have something like this:
private void OwnerServicesSlider_ItemSelected(object sender, ItemTappedEventArgs e)
{
var service = OwnerServicesSlider.SelectedItem as Services;
Navigation.PushAsync(service.Page);
}
It shows no errors but when I run it I get a
InvalidOperationException: 'Page must not already have a parent.
Any hint will be appreciated!
as Jason said,maybe the page you would push which is exist in thecurren navigation structure,there is a workaround ,before you push the page :
private void OwnerServicesSlider_ItemSelected(object sender, ItemTappedEventArgs e)
{
var service = OwnerServicesSlider.SelectedItem as Services;
service.Page.Parent = null;
Navigation.PushAsync(service.Page);
}

Xamarin Forms: System.ObjectDisposedException when setting Focus to an Entry control

I have the following Xamarin Forms page that throws an exception on this line...
The first time this page is loaded, the OnAppearing works fine, sets the focus properly, and doesn't throw an exception.
When I navigate back to this page (ie, logout), OnAppearing is throwing the following...
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'Xamarin.Forms.Platform.Android.EntryRenderer'.
What is the best way to set focus to a control on a page in Xamarin Forms?
I'm not sure what is in your XAML, but if you define the x:Name="_entry" on the Entry in XAML, and use that name to access the control directly instead of FindByName, it should work fine.
I try to reproduce your issue at my side, but it works fine and there is no issue when I click Button to navigate another page and coming back. Please take a look my code:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<Entry
x:Name="UserNameentry"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand" />
<Button
x:Name="btn1"
Clicked="btn1_Clicked"
HeightRequest="50"
HorizontalOptions="FillAndExpand"
Text="btn1"
VerticalOptions="CenterAndExpand"
WidthRequest="200" />
</StackLayout>
public Page4()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
var usernameentry = FindByName("UserNameentry") as Entry;
usernameentry.Focus();
}
private async void btn1_Clicked(object sender, EventArgs e)
{
Page3 page = new Page3();
await Navigation.PushModalAsync(page);
}
If you still have this issue, please provide some code about xaml here.

Xamarin.Forms: Save File dialog on Xamarin Android

I'm trying to save a file to the device.
The problem is that I'm hardcoding the filename from code behind.
My requirement is to ask the user to save a file with a user defined filename. How can I ask the user to save a file by opening a filesave dialog in Xamarin.Forms?
Have you solved it? Can you post your solution in case?
This question could fit your requirements, it uses this plugin: Xam.plugin.filepicker Xam.Plugin.FilePicker Works fine but can't get file
Here is the easiest popup page using Rg.Plugins.Popup
cs:
public partial class PromptPopup : PopupPage
{
public event EventHandler Oked;
public event EventHandler Canceled;
public PromptPopup(string title, string text)
{
InitializeComponent();
PopupText.Text = text;
PopupTitle.Text = title;
}
private void OnCancel(object sender, EventArgs e)
{
this.Canceled(sender, e);
PopupNavigation.PopAsync(false);
}
private void OnOk(object sender, EventArgs e)
{
this.Oked(sender, e);
PopupNavigation.PopAsync(false);
}
}
its xaml:
<StackLayout VerticalOptions="Center" HorizontalOptions="FillAndExpand" Padding="20, 20, 20, 20">
<StackLayout BackgroundColor="White" Padding="10, 10, 10, 10">
<Label x:Name="PopupTitle" Text="PromptPopupTitle" TextColor="Gray" FontSize="20" HorizontalOptions="Center" />
<ScrollView>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label x:Name="PopupText"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="Center"
TextColor="Gray"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Button Text="{i18n:Translate PopupButtonCancel}" Clicked="OnCancel" HorizontalOptions="FillAndExpand"></Button>
<Button Text="{i18n:Translate PopupButtonOk}" Clicked="OnOk" HorizontalOptions="FillAndExpand"></Button>
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
(this page comes from a PopupPage instead of ContentPage)
and you can call it like this
var page = new PromptPopup("title", "text");
page.Oked += Page_OkedLogout;
page.Canceled += Page_CanceledLogout;
await PopupNavigation.PushAsync(page);
further deep support: https://github.com/rotorgames/Rg.Plugins.Popup
You have to implement the file picker yourself, there's no built in way to do that, best to go out to GitHub and look around if that's what you're after.
It sounds to me like you could easily achieve what you're after by just popping a text box, having a user enter a file name, validate the filename with a regex or something and then just saving the file with that file name, you could even just save the file and give them the option to rename the file by listing them all out, but that's all too broad for me to give you an exact implementation, so the best I can do for you is tell you the simple way to do what you're wanting to do.
After selecting file you just open Popup with "Entry" and save file using Entry Text. you can open popup using "Rg.Plugins.Popup"

Using FFImageLoading:CachedImage in ListView

Been looking for an example online about this but can't seem to find one. Basically, i would like to use a FFImageLoading:CachedImage in a ListView with the source bound to a string with a url e.g. http://blah.com/image.jpg. This is what i have tried thus far but no image seems to be loaded.
<ListView IsVisible="true" ItemsSource="{x:Static local:viewmodel.TSViewModel.myArticles}">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Vertical">
<ffimageloading:CachedImage
HorizontalOptions="Center" VerticalOptions="Center"
WidthRequest="95" HeightRequest="95"
DownsampleToViewSize="true"
Source = "{Binding ImageUrl}">
</ffimageloading:CachedImage>
<Label Text="{Binding Title}" LineBreakMode="WordWrap" FontSize="Small"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
If there is something i'm doing wrong or i'm just not supposed to use it this way or there are better alternatives, please help me out. Also, i'm a beginner with xamarin forms and mvvm. Any help would be greatly appreciated.
Update: So the images do load but only once I move away from the images page to another page then back to the images page. The images are being loaded in a content page within a tabbed page so maybe that has something to do with it. Any ideas on how to load them the first time the tabbed page is opened?
HomePage.xaml.cs
using TestApp.view;
using Xamarin.Forms;
using TestApp.database;
namespace TestApp
{
public partial class HomePage : TabbedPage
{
public HomePage(TestAppDatabase db)
{
InitializeComponent();
Children.Add(new Bakeries(db));
Children.Add(new Bars());
Children.Add(new Butcheries());
Children.Add(new Restaurants());
Children.Add(new Supermarkets());
Children.Add(new Entertainment());
}
}
}
Bakeries.xaml.cs
using System.Collections.Generic;
using TestApp.model;
using TestApp.database;
using Xamarin.Forms;
namespace TestApp.view
{
public partial class Bakeries : ContentPage
{
public Bakeries(TestApp db)
{
InitializeComponent();
List<Eateries> bakeries = (List<Eateries>) db.GetBakeries();
bakeriesList.ItemsSource = bakeries;
}
}
}
According to the API docs located here. https://github.com/molinch/FFImageLoading/wiki/Xamarin.Forms-API
You must add this line to your platform specific project (AppDelegate.cs, MainActivity.cs, etc) before you use FFImageLoading:
CachedImageRenderer.Init();

Resources