Xamarin Android RecyclerView with CardView button clicked multiple times - onclick

I’m trying to make a RecyclerView with CardViews. Each CardView has multiple (4) buttons. The app runs fine but if I scroll in the RecyclerView when I press the button once it clicks/runs the code multiple times.
I know what the problem is but I can’t solve it. The buttons get delegated multiple times.
So how do I need to delegate my buttons in order to only run them ones even on scroll?
My RecyclerAdapter looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V7.Widget;
using MobileApp.Models;
using Android.Support.Design.Widget;
namespace MobileApp
{
public class EvenementRecyclerAdapter : RecyclerView.Adapter
{
private List<Knop> Knoppen;
private RecyclerView mRecyclerView;
private Context mContext;
private string mEvenementNaam;
public EvenementRecyclerAdapter(List<Knop> knoppen, RecyclerView recyclerView, Context context, string evenementNaam)
{
Knoppen = knoppen;
mRecyclerView = recyclerView;
mContext = context;
mEvenementNaam = evenementNaam;
}
public class MyView : RecyclerView.ViewHolder
{
public View mMainView { get; set; }
public TextView mName { get; set; }
public TextView mInfo { get; set; }
public TextView mSales { get; set; }
public Button mBtnOne { get; set; }
public Button mBtnTwo { get; set; }
public Button mBtnFive { get; set; }
public Button mBtnDeleteOne { get; set; }
public MyView(View view) : base(view)
{
mMainView = view;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View row = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.CardKnopEvenement, parent, false);
TextView knopNaam = row.FindViewById<TextView>(Resource.Id.knopNaam_cardview);
TextView knopInfo = row.FindViewById<TextView>(Resource.Id.knopInfo_cardview);
TextView aantalVerkocht = row.FindViewById<TextView>(Resource.Id.aantalVerkocht_cardview);
Button buttonOne = row.FindViewById<Button>(Resource.Id.btnOne);
Button buttonTwo = row.FindViewById<Button>(Resource.Id.btnTwo);
Button buttonFive = row.FindViewById<Button>(Resource.Id.btnFive);
Button buttonDeleteone = row.FindViewById<Button>(Resource.Id.btnDeleteOne);
MyView view = new MyView(row) { mName = knopNaam, mInfo = knopInfo, mSales = aantalVerkocht, mBtnOne = buttonOne, mBtnTwo = buttonTwo, mBtnFive = buttonFive, mBtnDeleteOne = buttonDeleteone };
return view;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
MyView myHolder = holder as MyView;
myHolder.mMainView.Click += mMainView_Click;
myHolder.mName.Text = Knoppen[position].Naam;
myHolder.mSales.Text = ConnectionDB.GetVerkochtAantal(mEvenementNaam, myHolder.mName.Text);
//Create button click events
myHolder.mBtnOne.Click += delegate {
Toast.MakeText(mContext, myHolder.mSales.Text, ToastLength.Short).Show();
};
myHolder.mBtnTwo.Click += delegate {
Toast.MakeText(mContext, myHolder.mSales.Text, ToastLength.Short).Show();
};
myHolder.mBtnFive.Click += delegate {
Toast.MakeText(mContext, myHolder.mSales.Text, ToastLength.Short).Show();
};
myHolder.mBtnDeleteOne.Click += delegate {
//Toast.MakeText(mContext, myHolder.mSales.Text, ToastLength.Short).Show();
};
}
void mMainView_Click(object sender, EventArgs e)
{
int position = mRecyclerView.GetChildAdapterPosition((View)sender);
}
public override int ItemCount
{
get { return Knoppen.Count; }
}
}
}
My app design looks like:
Xamarin Android app with RecyclerView and CardView
I didn't find anything I could use on the internet. Thanks in advance!
EDIT SOLVED
I fixed it by putting a if statement around my delegate to check if it had a OnClickListener
if (!myHolder.mBtnOne.HasOnClickListeners)
{
myHolder.mBtnOne.Click += delegate {
Toast.MakeText(mContext, myHolder.mSales.Text, ToastLength.Short).Show();
};
}

Related

Clear entry text from ViewModel using RelayCommand

I would like to clear entry text from my ViewModel which is binded there. In the code below I tried it by using a RelayCommand, but it doesn't work.
What i want to accomplish: When clicking button named AddQuestionToQuiz, a function is executed by using Command on the button. The function OnCreateQuizClick(), located in my ViewModel, is triggerd and this function needs to clear my entry text, which i don't get for the moment.
I also tried to use a regular Command instead of using a RelayCommand, but also here it doesn't want to work.
EDIT: UNDERNEATH CODE WORKS FINE - GOT UPDATED
Code is used to clear entry text when clicking on a button from your ViewModel, implementing INotifyPropertyChanged Interface
.xaml - code
<Button x:Name="AddQuestionToQuiz" WidthRequest="200" Command="{Binding CreateQuizCommand}" Style="{StaticResource ButtonStyle}" Text="Add question to quiz"></Button>
ViewModel - code
internal class CreateQuizPageViewModel : INotifyPropertyChanged
{
// Quiz Name Input
public String QuizNameInput { get; set; }
private String quizQuestionInput = "";
public String QuizQuestionInput
{
get { return quizQuestionInput; }
set { quizQuestionInput = value; OnPropertyChanged(); }
}
public RelayCommand CreateQuizCommand { get; set; }
public CreateQuizPageViewModel()
{
CreateQuizCommand = new RelayCommand(OnCreateQuizClick);
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void OnCreateQuizClick()
{
QuizQuestionInput = "";
}
}
EDIT: VIEWMODEL UPDATED
.xaml - code
<Button x:Name="AddQuestionToQuiz" WidthRequest="200" Command="{Binding CreateQuizCommand}" Style="{StaticResource ButtonStyle}" Text="Add question to quiz"></Button>
ViewModel - code
internal class CreateQuizPageViewModel : INotifyPropertyChanged
{
// Quiz Name Input
public String QuizNameInput { get; set; }
private String quizQuestionInput = "";
public String QuizQuestionInput
{
get { return quizQuestionInput; }
set { quizQuestionInput = value; OnPropertyChanged(); }
}
public RelayCommand CreateQuizCommand { get; set; }
public CreateQuizPageViewModel()
{
CreateQuizCommand = new RelayCommand(OnCreateQuizClick);
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void OnCreateQuizClick()
{
QuizQuestionInput = "";
}
}

Using SQLite-net-pcl and can't update the data

So i have this really annoying problem where i Can't seem to get it to update any of the databases i have created, whats worse the i can see the instance is showing the updated information but isn't applying it. I'm really new to this and is my first course project.
This is the code that is being used to update the data:
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.SuperPages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.UpdateDeleteListItem
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class UpdateDeleteList : ContentPage
{
private new readonly Label Title;
private Style LabelStyle;
private StoreDetails UpdateStoreDetails;
private Entry SNum;
private Entry SName;
private Entry SMName;
private Entry Addy;
public UpdateDeleteList(string pageType, object Item)
{
InitializeComponent();
BindingContext = Item;
UpdateStoreDetails = (StoreDetails)Item;
SetLabelStyle();
string titleMsg = "Update or Delete Selected " + pageType;
Frame frame = new Frame();
Label title = new Label() {Text = titleMsg };
Title = title;
StackLayout titleStack = new StackLayout() { Children = { Title } };
frame.Content = titleStack;
if (pageType == "Store")
{
StoreUDLItem(frame);
}
if (pageType == "Ticket")
{
TicketUDLItem(frame);
}
StylePage();
}
private void SaveButton_Clicked(object sender, EventArgs args)
{
if (StoreCheckValues() == true)
{
var store = SName;
var storeManager = SMName;
var storeNumber = SNum;
var address = Addy;
var storeDataAccess = new StoreDataAccess();
UpdateStoreDetails.StoreName = store.Text;
UpdateStoreDetails.StoreManger = storeManager.Text;
UpdateStoreDetails.StoreNumber = storeNumber.Text;
UpdateStoreDetails.Address = address.Text;
//MerchandiserKey = GetMerchId()
storeDataAccess.SaveStoreDetails(UpdateStoreDetails);
storeDataAccess.SaveAllStoreDetails();
}
'''
here is the data access methods:
'''
using Project.DataClasses;
using SQLite;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using Xamarin.Forms;
namespace Project.Database
{
class StoreDataAccess
{
private SQLiteConnection database;
private static object collisionLock = new object();
public ObservableCollection<StoreDetails> StoreDetails { get; set; }
public StoreDataAccess()
{
database = DependencyService.Get<IDatabaseConnection>().DbConnectionStore();
database.CreateTable<StoreDetails>();
this.StoreDetails = new ObservableCollection<StoreDetails>(database.Table<StoreDetails>());
//AddNewTicket(new Ticket ticket);
}
//add ticket method
public void AddNewStore(StoreDetails item)
{
this.StoreDetails.Add(item);
}
//retrieve ticket method
public StoreDetails GetStoreDetails(int id)
{
lock (collisionLock)
{
return database.Table<StoreDetails>().FirstOrDefault(StoreDetails => StoreDetails.StoreId == id);
}
}
//save ticket
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
public void SaveAllStoreDetails()
{
lock (collisionLock)
{
foreach (var storeDetailsInstance in this.StoreDetails)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
}
else
{
database.Insert(storeDetailsInstance);
}
}
}
}
'''
This is the page that is sending the information to the first code block to bind the data too
'''
using Project.Database;
using Project.DataClasses;
using Project.Pages.UpdateDeleteListItem;
using SQLite;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Project.Pages.ListPages
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StoreList : ContentPage
{
private ObservableCollection<StoreDetails> Items { get; set; }
private readonly StoreDataAccess storeDataAccess;
private readonly SQLiteConnection database;
public StoreList()
{
InitializeComponent();
storeDataAccess = new StoreDataAccess();
this.BindingContext = this.storeDataAccess;
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item == null) { return; }
else
{
//var id = Items[e.ItemIndex].StoreId;
await Navigation.PushAsync(new UpdateDeleteList("Store", e.Item));
//Deselect Item
((ListView)sender).SelectedItem = null;
}
}
//page reload handle
protected override void OnAppearing()
{
base.OnAppearing();
var dbName = "StoreListDatabase.db3";
var path = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.Personal), dbName);
if (database == null)
{
new StoreDataAccess();
}
using (SQLiteConnection conn = new SQLiteConnection(path))
{
Items = storeDataAccess.StoreDetails;
StoreView.ItemsSource = Items;
}
}
}
}
'''
and lastly here is my databbase model for it:
'''
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using SQLite;
using System.ComponentModel;
namespace Project.DataClasses
{
class StoreDetails : INotifyPropertyChanged
{
private int _storeId;
[PrimaryKey, AutoIncrement, NotNull]
public int StoreId
{
get { return _storeId; }
set { _storeId = value; OnPropertyChanged(nameof(StoreId)); }
}
private string _storeName;
[NotNull, DefaultValue("Enter Store Name")]
public string StoreName
{
get { return _storeName; }
set { _storeName = value; OnPropertyChanged(nameof(_storeName)); }
}
private string _storeManger;
[NotNull, DefaultValue("Enter Store Managers Name")]
public string StoreManger
{
get { return _storeManger; }
set { _storeManger = value; OnPropertyChanged(nameof(StoreManger)); }
}
private string _storeNumber;
[NotNull, DefaultValue("Enter Store Number")]
public string StoreNumber
{
get { return _storeNumber; }
set { _storeNumber = value; OnPropertyChanged(nameof(StoreNumber)); }
}
private string _address;
[NotNull, DefaultValue("Enter Address")]
public string Address
{
get { return _address; }
set { _address = value; OnPropertyChanged(nameof(Address)); }
}
private int _merchandiserKey;
[NotNull]
public int MerchandiserKey
{
get { return _merchandiserKey; }
set { _merchandiserKey = value; OnPropertyChanged(nameof(MerchandiserKey)); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
'''
any help would be greatly appreciated
'''
public int SaveStoreDetails(StoreDetails storeDetailsInstance)
{
lock (collisionLock)
{
if (storeDetailsInstance.StoreId != 0)
{
database.Update(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
else
{
database.Insert(storeDetailsInstance);
return storeDetailsInstance.StoreId;
}
//database.Commit();
}
}
'''
this is the area where it all seems to be going wrong i just don't know why
Thank You Jason, you were correct in that the error was in calling both the savefunctions and overwriting it!!

Why my diffutils dont update my position in background

I'm using DiffUtils to update my Recyclerview.
Visually works but clicking an item returns it to me a position that does not match the item I clicked
I used NotifyDataChange that was able to solve the position problem. But visually, the last item is misconfigured.
I try to use NotifyDataChange that was able to solve the position problem. But visually, the last item is misconfigured.
My adapter:
class AdapterUser : RecyclerView.Adapter
{
//Global Var
public event EventHandler<int> ItemClick;
public List<Class.Result> ClassUser;
public Android.Content.Context context;
public class UserViewHolder : RecyclerView.ViewHolder
{
public static TextView txtName { get; set; }
public static TextView txtEspecialidade { get; set; }
public static CircleImageView Imagem { get; set; }
public static Bitmap bitmap { get; set; }
public static CircleImageView status { get; set; }
public static Button button { get; set; }
public UserViewHolder(View itemview, Action<int> listener) : base(itemview)
{
UserViewHolder.txtName = itemview.FindViewById<TextView>(Resource.Id.nameUser);
UserViewHolder.txtEspecialidade = itemview.FindViewById<TextView>(Resource.Id.speciality);
UserViewHolder.Imagem = itemview.FindViewById<CircleImageView>(Resource.Id.avatarUser);
UserViewHolder.status = itemview.FindViewById<CircleImageView>(Resource.Id.status);
UserViewHolder.button = itemview.FindViewById<Button>(Resource.Id.BtCriar);
}
}
public AdapterUser(List<Class.Result> user)
{
ClassUser = user;
}
public override int ItemCount
{
get { return ClassUser.Count(); }
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
//Method to transform the uri to bitmap
async Task MyMethodAsync()
{
// Do asynchronous work.
UserViewHolder.Imagem.SetImageBitmap(await Droid.Class.Functions.GetImageBitmapFromUrlAsync(ClassUser[position].PhotoUri));
};
UserViewHolder userHolder = holder as UserViewHolder;
if (ClassUser[position].PhotoUri != null)
{
MyMethodAsync();
}
else
{
UserViewHolder.Imagem.SetImageResource(Resource.Drawable.avatar);
}
if (ClassUser[position].IsOnline != true)
{
UserViewHolder.status.Visibility = ViewStates.Invisible;
}
else
{
UserViewHolder.status.Visibility = ViewStates.Visible;
}
UserViewHolder.txtName.Text = ClassUser[position].Name;
UserViewHolder.txtEspecialidade.Text = ClassUser[position].Specialty;
UserViewHolder.button.Click += (sender, args) =>
{
Toast.MakeText(context, ClassUser[position].Name, ToastLength.Short).Show();
Console.WriteLine(ClassUser[position].Name);
};
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ResultUser, parent, false);
UserViewHolder vh = new UserViewHolder(itemView, OnClick);
context = parent.Context;
return vh;
}
private void OnClick(int obj)
{
}
public void Update(List<Class.Result> oldList, List<Class.Result> newList)
{
// Set detectMoves to true for smoother animations
MyDiffCallback callback = new MyDiffCallback(oldList, newList);
DiffUtil.DiffResult result = DiffUtil.CalculateDiff(callback);
this.ClassUser.Clear();
this.ClassUser.AddRange(newList);
// Despatch the updates to your RecyclerAdapter
result.DispatchUpdatesTo(this);
}
My DiffUtills:
class MyDiffCallback : DiffUtil.Callback
{
List<Class.Result> newList;
List<Class.Result> oldList;
public MyDiffCallback(List<Class.Result> oldList, List<Class.Result> newList)
{
this.oldList = oldList;
this.newList = newList;
}
public override int NewListSize => newList.Count;
public override int OldListSize => oldList.Count;
public override bool AreContentsTheSame(int oldItemPosition, int newItemPosition)
{
return oldList[oldItemPosition].IsOnline == newList[newItemPosition].IsOnline;
}
public override bool AreItemsTheSame(int oldItemPosition, int newItemPosition)
{
return oldList[oldItemPosition].RowKey == newList[newItemPosition].RowKey;
}
public override Java.Lang.Object GetChangePayload(int oldItemPosition, int newItemPosition)
{
return base.GetChangePayload(oldItemPosition, newItemPosition);
}
}
My activity:
ClassUtilizador = Data.Result.ToString();
Class.ClassUtilizador classUser = JsonConvert.DeserializeObject<Class.ClassUtilizador>(Data.Result.ToString());
//Call the function to update item
adapter.Update(classUserOld.Result, classUser.Result);
//Clean class and put the new data
classUserOld = new Class.ClassUtilizador();
classUserOld = classUser;
Update items, remove, add ou move items. Depending of my request.
You should call:
holder.bindingAdapterPosition
clicking an item returns it to me a position that does not match the
item I clicked
UserViewHolder.button.Click += (sender, args) =>
{
Toast.MakeText(context, ClassUser[position].Name, ToastLength.Short).Show();
Console.WriteLine(ClassUser[position].Name);
};
change to :
UserViewHolder.button.Tag = position;
UserViewHolder.button.SetOnClickListener(this);
then let your adapter extends View.IOnClickListener
class AdapterUser : RecyclerView.Adapter,View.IOnClickListener
public void OnClick(View v)
{
//here you could get the correct position
Toast.MakeText(context, v.Tag.ToString(), ToastLength.Short).Show();
}
if it doesn't update your Recyclerview, you could add the method in your adapter:
public void setData(List<Class.Result> newList)
{
this.ClassUser= new List<Class.Result>(newList);
}
in your update method :
public void Update(List<Class.Result> oldList, List<Class.Result> newList)
{
// Set detectMoves to true for smoother animations
MyDiffCallback callback = new MyDiffCallback(oldList, newList);
DiffUtil.DiffResult result = DiffUtil.CalculateDiff(callback);
this.ClassUser.Clear();
this.ClassUser.AddRange(newList);
setData(this.ClassUser);
// Despatch the updates to your RecyclerAdapter
result.DispatchUpdatesTo(this);
}

Making a CardView clickable to load an activity with the same firebase data

i'm facing a small issue figuring out on the following -
I have a RecyclerView in my MainActivity, the RecyclerView has CardView within it.
The data displays on the MinActivity page, cuz the RecyclerView is in it.
Now, I want a new activity to pop-up once a CardView is clicked.
The new activity will use the same data as the CardView had.
I'm using Firebase storage if it matters.
Example -
My CardView 1 has a name, age and country - Jake, 19, UK.
The other activity will get the collection data from Firebase which is the exact same as CardView 1 and implement it in to the new activity.
I hope I explained it well..
(I'm using getters and setters)
My code so far (Only the needed parts)-
MainActivity
list_post = new ArrayList<>();
list_header = new ArrayList<>();
postsAdapter = new PostsAdapter(list_post);
headerAdapter = new HeaderAdapter(list_header);
headerRecycler = (RecyclerView) findViewById(R.id.headerRecycler);
headerRecycler.setAdapter(headerAdapter);
headerRecycler.setLayoutManager(new LinearLayoutManager(this));
firebaseFirestore = FirebaseFirestore.getInstance();
firebaseFirestore.collection("FeaturedPosts").limit(1).addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot queryDocumentSnapshotss, FirebaseFirestoreException ee) {
for (DocumentChange doc2: queryDocumentSnapshotss.getDocumentChanges()) {
if (doc2.getType() == DocumentChange.Type.ADDED) {
ListForHeader listForHeader = doc2.getDocument().toObject(ListForHeader.class);
list_header.add(listForHeader);
headerAdapter.notifyDataSetChanged();
}
}
}
});
RecyclerAdapter
public class HeaderAdapter extends RecyclerView.Adapter<HeaderAdapter.ViewHolder2> {
public List<ListForHeader> list_header;
public Context contextt;
public HeaderAdapter (List<ListForHeader> list_header) {
this.list_header = list_header;
}
#NonNull
#Override
public HeaderAdapter.ViewHolder2 onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.featured_activity, parent, false);
contextt = parent.getContext();
return new HeaderAdapter.ViewHolder2(view);
}
#Override
public void onBindViewHolder(#NonNull HeaderAdapter.ViewHolder2 holder, int position) {
String header_data2 = list_header.get(position).getHeader2();
holder.setHeaderText2(header_data2);
String date_data2 = list_header.get(position).getDate2();
holder.setDateText2(date_data2);
String image_data2 = list_header.get(position).getImage_url2();
holder.setIntroIMG2(image_data2);
}
#Override
public int getItemCount() {
return list_header.size();
}
public class ViewHolder2 extends RecyclerView.ViewHolder {
private View mView;
private ImageView introIMG2;
private TextView headerText2;
private TextView dateText2;
public ViewHolder2(View itemView) {
super(itemView);
mView = itemView;
}
public void setHeaderText2(String headText2) {
headerText2 = mView.findViewById(R.id.introHeader2);
headerText2.setText(headText2);
}
public void setDateText2(String tarihText2) {
dateText2 = mView.findViewById(R.id.introDate2);
dateText2.setText(tarihText2);
}
public void setIntroIMG2 (String downloadUri) {
introIMG2 = (ImageView) mView.findViewById(R.id.introImage2);
Glide.with(contextt).load(downloadUri).into(introIMG2);
}
}
}
As far as I see its simple issue. You can add cardview Id to viewHolder and set onlclicklister to it in bindview and in on click Start activity and pass the current data in Intent. Let me know if its something else stopping you from sending data or getting click on cardview.
Extra: you may have to set cardview clickable true.
here is the example.
class DemoViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
#BindView(R.id.card)
CardView cardView;
public DemoViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
cardView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.card:
doSomethingOn(mList.get(getAdapterPosition()))
break;
}
}
public class BookingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
Context mContext;
ArrayList<Booking> mList;
public BookingAdapter(Context context, ArrayList<Booking> list) {
mContext = context;
mList = list;
this.cancelBookingListener = cancelBookingListener;
}

Calling GetImageAsPngAsync of FFImageLoading from ViewModel class?

Using https://github.com/luberda-molinet/FFImageLoading for Xamarin Forms
My XAML:
<forms:CachedImage
CacheType="All"
RetryDelay="1000"
DownsampleHeight="150"
RetryCount="5"
CacheDuration="1"
BackgroundColor="WhiteSmoke"
BitmapOptimizations="True"
SuccessCommand="{Binding CcCommand}"
Source = "{Binding Photo1}">
My ViewModel Class:
class AboutMeViewModel : INotifyPropertyChanged
{
public ICommand CcCommand { get; set; }
public AboutMeViewModel()
{
CcCommand = new Command<CachedImageEvents.SuccessEventArgs>(ffFinishLoading);
}
void ffFinishLoading(CachedImageEvents.SuccessEventArgs ea)
{
// Here I would like to call 'GetImageAsPngAsync'
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
At ffFinishLoading I would like to call GetImageAsPngAsync but I can't find a way to do it at ViewModel class as I have no option for reference forms:CachedImage from the XAML file to ViewModel file.
Any help will be much appreciated.
var stream = await ImageService.Instance.LoadUrl(Photo1).AsPNGStreamAsync();

Resources