ListView not deleting items in Xamarin.Forms. I have assigned an ObservableCollection to the ListView itemsource. MVVM - c#

In my Xamarin.Forms app I have a simple Contact class [Model]. In the UI [View] there exists a ListView that displays the Contacts. In my model view class I have a list of Contacts (_listOfContacts) that is assigned to the itemSource property of the ListView. This list of Contacts is an ObservableCollection. My issue is the when user clicks Delete from ContextActions I can see that the _listOfContacts is updated but the ListView is not.
The ListView is only updated when I reassign its itemsource to the _listOfContacts. This should not be needed if _listOfContacts is an ObservableCollection of Contacts.
I am new to MVVM so I need to clear these basic MVVM concepts before I go on to learn more advanced techniques.
Here is my code:
Model
class Contact
{
public String Name { get; set; }
public String Status { get; set; }
public String ImageUrl { get; set; }
}
Model View
public partial class ContactListPage : ContentPage
{
private ObservableCollection<Contact> _listOfContacts;
public ContactListPage()
{
InitializeComponent();
_listOfContacts = new ObservableCollection<Contact>
{
new Contact {Name="Item1", ImageUrl="http://lorempixel.com/100/100/people/1" , Status="Hey"},
new Contact { Name = "Item2", ImageUrl = "http://lorempixel.com/100/100/people/2", Status="Hey" },
};
contactList.ItemsSource = _listOfContacts.ToList();
}
private void EditContactClick(object sender, EventArgs e)
{
DisplayAlert("Alert", "Clicked Edit", "Cancel");
}
private void DeleteContactClick(object sender, EventArgs e)
{
var contact = (sender as MenuItem).CommandParameter as Contact;
_listOfContacts.Remove(contact);
//following line of code should not be needed since _listOfContacts is
//an ObservableCollection and removing an item should update the bound control automatically
**contactList.ItemsSource = _listOfContacts.ToList();**
}
}
View
<ContentPage.Content>
<StackLayout>
<ListView x:Name="contactList" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="10">
<Image Source="{Binding ImageUrl}"/>
<StackLayout HorizontalOptions="StartAndExpand">
<Label Text="{Binding Name}" Margin="0,2,0,2"/>
<Label Text="{Binding Status}" Margin="0,2,0,2" />
</StackLayout>
</StackLayout>
<ViewCell.ContextActions>
<MenuItem Text="Edit" Clicked="EditContactClick" CommandParameter="{Binding .}"/>
<MenuItem Text="Delete" Clicked="DeleteContactClick" IsDestructive="True" CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>

I have tested your code, it is just the method ToList()which caused this question:
contactList.ItemsSource = _listOfContacts.ToList();
At the beginning, the type of _listOfContacts is ObservableCollection, but when you use the method ToList(),then it will been converted to List again.
So just delete the method 'ToList()', your code will work properly, just as follows:
contactList.ItemsSource = _listOfContacts;

Remove .toList() from contactList.ItemsSource = _listOfContacts.ToList(); and try again.
_listOfContacts is an ObservableCollection which should be used as your ItemsSource directly. Maybe go and check out the ObservableCollection documentation.

Related

Xamarin Android MVVM - Grouped CollectionView does not update UI after list changes

I have a grouped CollectionView with an ObservableCollection as ItemSource andthe list shows just fine,  with the itens grouped. The problem is that the UI does not get updated when i add or remove something from the collection. I need to pop and call the ProductsPage again to see the changes.
I even tried to refresh the entire list by calling the CreateGroups method after a change, it didn't work either.
Here´s parte of the code (i removed some unrelated code so there may be some inconsistencies)
ProdutosGroup
public class ProdutosGroup : ObservableCollection<Produto>
{
public string Titulo { get; set; }
public ProdutosGroup(string titulo, ObservableCollection<Produto> produtos) : base(produtos)
{
Titulo = titulo;
}
}
ProductsViewModel
public ObservableCollection<Produto> Produtos { get; set; } //the actual list of products
public ObservableCollection<ProdutosGroup> ProdutosAgrupadosList { get; set; }//the grouped list
public ListaDeProdutosViewModel(int idListaDeProdutos)
{
PopulateList();
CreateGroups();
}
public void CarregarProdutos()
{
this.Produtos = new ObservableCollection<Produto(App._produtoRepo.GetProdutos);
}
public void CreateGroups()
{
var idsCat = Produtos.Select(x => x.IdCategoria).Distinct();
var cats = new ObservableCollection<ProdutoCategoria>();
foreach (var idCat in idsCat)
{
cats.Add(App._categoriaRepo.GetProdutoCategoriaById(idCat));
}
foreach (var item in cats)
{
ObservableCollection<Produto> produtosDaCategoria = new ObservableCollection<Produto>();
foreach (var prod in Produtos)
{
if (prod.IdCategoria == item.Id)
produtosDaCategoria.Add(prod);
}
ProdutosAgrupadosList.Add(new ProdutosGroup(item.Descricao, new ObservableCollection<Produto>(produtosDaCategoria)));
}
}
ProductsPage
<ContentPage.Content>
<Grid>
<ScrollView >
<CollectionView ItemsSource="{Binding ProdutosAgrupadosList}" x:Name="Listas" IsGrouped="true">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:ProdutosGroup">
<Label Text="{Binding Titulo}" FontSize="28"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Produto">
<Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
<ImageButton Padding="12" Source="BasketPlus" Grid.Row="1" Command="{Binding AddForm}" HorizontalOptions="End" WidthRequest="68" HeightRequest="68" VerticalOptions="End" CornerRadius="100" Margin="0,0,16,22" BackgroundColor="{StaticResource Verde}"/>
</Grid>
</ContentPage.Content>
If you want to add an item in a group, you could simply use the following code:
ProdutosAgrupadosList[0].Add(
new Produto
{
Nome = "and"
}); // this will add the item at the end
or
ProdutosAgrupadosList[0].Insert(1,
new Produto
{
Nome = "and"
}); // add the item after the index1 item
To remove, you could either use ProdutosAgrupadosList[0].RemoveAt(index) or use a SwipeView which you could refer to CollectionView Context menus for more info. A simple demo using SwipeView like the following
<CollectionView.ItemTemplate>
<DataTemplate >
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="LightPink"
Command="{Binding Source={x:Reference Listas}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.LeftItems>
<StackLayout>
<Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
</StackLayout>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
That works for me based on the code in your question. For more info, you could refer to Xamarin.Forms CollectionView
Hope it works for you.

Collection's View Label pass to modal upon tapping the collection view item

My problem is I want to pass the label in my collection view to a modal page upon tapping a collection view items.
this is my homepage.xml.cs code:
`
async private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
await PopupNavigation.Instance.PushAsync(OrderPageModal);
}
This is my homepage.xml
<StackLayout
Style="{StaticResource itemsInsideCardViewStackLayoutStyle}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</StackLayout.GestureRecognizers>
<Frame
Style="{StaticResource stationImageFrameStyle}">
<Image
Style="{StaticResource stationImageStyle}"
Source="{Binding ImageURL}" />
</Frame>
<StackLayout
Style="{StaticResource detailsStackLayout}">
<Label
Text="{Binding storename}"
Style="{StaticResource NameLabel}"
HorizontalOptions="CenterAndExpand"
Margin="-40,0,0,0"/>
`
that Text="{Binding storename}" is I get here;( in one file,I just put together my station/store model and the IEnumerable Get().
`
public static IEnumerable<WRSinfo> Get()
{
return new List<WRSinfo>
{
new WRSinfo()
{
storename="Aqua Refilling Station", status="Open", ImageURL="water_ref.png", distance="2km"
},
};
}
public string storename { get; set; }
public string distance { get; set; }
public string status { get; set; }
`
this is my popupmodal page design:
`
<StackLayout BackgroundColor="Green"
HorizontalOptions="Center"
VerticalOptions="Start"
WidthRequest="100">
<Label Text="{Binding storename}" FontSize="20" TextColor="Black" x:Name="lblTextStorname" />
</StackLayout>
`
So what ouput I expect is. If I click collection view item which a name of store, then upon clicking it, a popupmodal will appear then also the name of the store I clicked from collectionview item.
Im newbie to this project and tech, pls help me sir. All comment will be appreciated.
output should be like this. enter image description here
According to the picture you provide, I recommend you to use the Xamarin.Forms Shell navigation.
You can change the TapGestureRecognizer_Tapped method to pass the Name of the WRSinfo to the SecondPage.
async private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
string WRSinfoName = (e.CurrentSelection.FirstOrDefault() as WRSinfo).Name;
await Shell.Current.GoToAsync($"SecondPage?name={WRSinfoName}");
}
Then in the SecondPage.xmal.cs you should use the code [QueryProperty(nameof(Name), "name")] to accept the data.
[QueryProperty(nameof(Name), "name")]
public partial class SecondPage : ContentPage
{
public string Name
{
set
{
LoadWRSinfo(value);
}
}
void LoadWRSinfo(string name)
{
try
{
WRSinfo wRSinfo = WRSinfoData.WRSinfo.FirstOrDefault(a => a.storename== name);
BindingContext = wRSinfo;
}
catch (Exception)
{
Console.WriteLine("Failed to load. ");
}
}
}
This is a sample you can refer to. I am not clear about the data structure you use. So you can follow the sample here the Microsoft provided Download the sample.

Should ViewModels inherit other ViewModels in Xamarin.Forms?

Should ViewModels inherit other ViewModels?
I have a MerchandiserViewModel that contains the basic properties and database functions for a Merchandiser model.
The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView
MerchandiserViewModel.cs
public MerchandiserViewModel : INotifyPropertyChanged
{
// Property to hold the selected Merchandiser
// Generally I would make this static but then I can't bind the property
public Merchandiser SelectedMerchandiser {get; set;}
// Other logic...
}
The MerchandiserViewModel is instantiated as a Static Resource in App.xaml so that I only have one instance of the view model.
App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MobileApp.App"
xmlns:ViewModels="clr-namespace:MobileApp.ViewModels">
<Application.Resources>
<ViewModels:MerchandiserViewModel x:Key="MerchandiserViewModel" />
<ViewModels:MerchandiserProfileViewModel x:Key="MerchandiserProfileViewModel" />
</Application.Resources>
</Application>
For each View related to a Merchandiser e.g. MerchandiserProfile, EditProfile etc. I create a new ViewModel and inherit the MerchandiserViewModel
MerchandiserProfileViewModel.cs inherits the MerchandiserViewModel
public class MerchandiserProfileViewModel : MerchandiserViewModel
{
// Logic Specific to the Merchandiser Profile View
}
The problem is... when I create a new [Page]ViewModel and inherit the "MerchandiserViewModel" I receive the following error message.
I think this may be because a new instance of the MerchandiserViewModel is created so I am not referencing the initial SelectedMerchandiser property.
This makes me think that inheriting ViewModels isn't a good idea?
How is this situation usually handled? Should I just jam all logic for each page/view into the one MerchandiserViewModel? I want my code to be as clean an separated as possible, so would like to avoid this if possible.
AFTER THOUGHT
Am I able to access the properties of the MerchandiserViewModel in static Resource in C#? this way I could pass the required properties to the new ViewModel without inheriting the MerchandiserViewModel ... keen to hear thoughts on this?
The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView
According to your description, you want to binding for ListView, for MerchandiserViewModel, you don't need to inherit other ViewModels, I suggest you can take a look the Model-View-ViewModel Pattern
I do one sample that binding ListView using MVVM, please take a look.
<StackLayout>
<ListView
x:Name="listview1"
HasUnevenRows="True"
ItemsSource="{Binding mers}"
SelectedItem="{Binding selecteditem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
The model class,contains some properties that binding to UI.
public class Merchandiser
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
The MerchandiserViewmodel class, the view model implements properties and commands to which the view can data bind to, and notifies the view of any state changes through change notification events. The properties and commands that the view model provides define the functionality to be offered by the UI, but the view determines how that functionality is to be displayed.
public class MerchandiserViewmodel:ViewModelBase
{
public ObservableCollection<Merchandiser> mers { get; set; }
private Merchandiser _selecteditem;
public Merchandiser selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
RaisePropertyChanged("selecteditem");
}
}
public MerchandiserViewmodel()
{
mers = new ObservableCollection<Merchandiser>();
getdata();
}
private void getdata()
{
for(int i=0;i<20;i++)
{
Merchandiser mer = new Merchandiser();
mer.Name = "merchandiser "+i;
mer.PhoneNumber = "123";
mers.Add(mer);
}
}
}
The ViewModelBase is class that implementinf INotifyPropertyChanged interface, notify data changed. For MerchandiserViewmodel, the Selected Merchandiser(selecteditem) must implement INotifyPropertyChanged to notify data change when you selected item from ListView every time.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Binding ViewModel to ContentPage
public partial class Page10 : ContentPage
{
public Page10()
{
InitializeComponent();
this.BindingContext = new MerchandiserViewmodel();
}
}
Update:
If you want to navigate to detailed page when select ListView item, you can use constructor pass by value in ListView_ItemSelected event.
<StackLayout>
<ListView
x:Name="listview1" ItemSelected="listview1_ItemSelected" SelectionMode="Single"
HasUnevenRows="True"
ItemsSource="{Binding mers}"
SelectedItem="{Binding selecteditem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
private async void listview1_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
Merchandiser item = (Merchandiser)e.SelectedItem;
await Navigation.PushAsync(new simplecontrol.Page29(item));
}
Detailed Page:
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name: " />
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PhoneNumber: " />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
public partial class Page29 : ContentPage
{
public Page29(Merchandiser mer)
{
InitializeComponent();
this.BindingContext = mer;
}
}

Xamarin.forms MVVM. Listview remains empty

I'm very new to Xamarin.Forms and MVVM and posting questions here on StackOverflow so bear with me please. I'm trying to fill a listview in Xamarin.Forms. I first programmed it without MVVM and it all worked like I wanted it to, but now I wanted to get in in MVVM and that is where it went wrong, now my list won't fill up anymore.
I made a viewmodel and only put all the binding in the viewmodel, I have not yet implemented eventhandlers.
This is a part of the code behind (I have a couple more eventhandlers but that is not relevant right now):
namespace CCXamarinApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PatientsWithTagPage : ContentPage
{
public PatientsWithTagPage()
{
BindingContext = new PatientsWithTagViewModel();
InitializeComponent();
(BindingContext as PatientsWithTagViewModel).GetAllPatients();
if((BindingContext as PatientsWithTagViewModel).IsEmptyPatientList)
HandleEmptyList();
else
(BindingContext as PatientsWithTagViewModel).SortAndShowPatients();
}
private void SearchBar_OnTextChanged(object sender, TextChangedEventArgs e)
{
(BindingContext as PatientsWithTagViewModel).Searching(e.NewTextValue);
}
...
This is my XAML page:
<SearchBar x:Name="SearchBar" Placeholder="Zoek op naam of plaats..." HeightRequest="25" Margin="10"
TextChanged="SearchBar_OnTextChanged"/>
<Label Text="{Binding LastRefreshed}" FontAttributes="Italic" FontSize="15" />
<Label x:Name="LabelEmptyList" FontSize="17" Text="Geen gegevens gevonden" FontAttributes="Bold"
IsVisible="False" />
<ListView x:Name="PatientListView" HasUnevenRows="True" SeparatorColor="Accent"
VerticalOptions="FillAndExpand" IsPullToRefreshEnabled="True" IsRefreshing="{Binding IsFetchingData, Mode=TwoWay}"
Refreshing="PatientListView_OnRefreshing" SelectedItem="{Binding SelectedPatient, Mode=TwoWay}"
ItemSelected="PatientListView_OnItemSelected" ItemsSource="{Binding Patients}"
IsVisible="True" BackgroundColor="Aqua">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Spacing="4">
<StackLayout Orientation="Horizontal" Margin="10,7,10,1">
<Label Text="{Binding FullName}" FontAttributes="Bold" FontSize="16" />
<Label Text="{Binding DisplayTimeOfLastScan, StringFormat='{0}'}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal" Margin="10,0,10,7">
<Label Text="{Binding LastLocation}" HorizontalOptions="Start" />
<Label Text="{Binding DisplayDurationSinceLastScan, StringFormat='al {0}'}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
This is my viewmodel (not all the code but the code that is most relevant). The BaseViewModel it derives from is from the nuget package "Refractored.Mvvmhelpers":
class PatientsWithTagViewModel : BaseViewModel
{
public ObservableCollection<PatientViewModel> Patients { get; private set; } = new ObservableCollection<PatientViewModel>();
private PatientViewModel selectedPatient;
public PatientViewModel SelectedPatient
{
get => selectedPatient;
set => SetProperty(ref selectedPatient, value);
}
private readonly JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
{
DateFormatString = "dd-MM-yyyTH:mm",
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
};
public bool IsEmptyPatientList => Patients.Count == 0;
private string testJson = "[{\"firstName\":\"P.\",\"lastName\":\"Selie\",\"tag\":{\"tagId\":\"124\",\"tagSerialNumber\":\"ABC135\"},\"scans\":[{\"location\":\"Tuin\",\"dateTime\":\"May01,2018,10:10\"},{\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,10:15\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,11:10\"},{\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,12:09\"}],\"id\":\"dcc4fe9929b3681f\"}," +
"{\"firstName\":\"W.\",\"lastName\":\"Janssens\",\"tag\":{\"tagId\":\"132\",\"tagSerialNumber\":\"ABC167\"},\"scans\":[{\"location\":\"Kamer23\",\"dateTime\":\"May01,2018,23:39\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:10\"},{\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,04:11\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:20\"},{\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,04:22\"}],\"id\":\"a6dac28475327922\"}]";
public void GetAllPatients()
{
IsFetchingData = true;
try
{
Patients = new ObservableCollection<PatientViewModel>(
JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson,
jsonSerializerSettings));
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
IsFetchingData = false;
}
}
This is the model I use:
public class Patient : ObservableObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Tag Tag { get; set; }
public List<Scan> Scans { get; set; }
public string Id { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}
It also has its own viewmodel with properties like DisplayDurationSinceLastScan, but I don't think it is relevant here, if you think it is, let me know.
So with this code I get my page but there seems to be no items in the list, if I debug, Patients is filled with items so it is not empty at all, but something goes wrong with the binding I guess but no error is given.
Here is a picture of what I get: the listview is shown (I added a blue background so I would know if the listview was visible or not), but there are no items in there. Still Patients is filled when I debug the app.
Does someone see the mistake I made?
I see some issues with your code here from a maintainability point of view. Try to keep all your code inside the view model instead of both the view model and code behind. Ideally, your code behind contains nothing and if anything it strictly has to do with visual things.
Anyway, in regard to you problem: you are creating a new ObservableCollection each time. That breaks the binding. Just keep the new ObservableCollection at the top and then when new data comes in, clear that and repopulate it. Like this:
public void GetAllPatients()
{
IsFetchingData = true;
try
{
var resultPatients = JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson, jsonSerializerSettings);
Patients.Clear();
foreach (var patient in resultPatients)
Patients.Add(patient);
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
IsFetchingData = false;
}
}
Your data should now show up.

Xamarin.Forms TapRecognizer on android cancels ItemTapped Event

I have created a custom control on Xamarin Forms that contains a gesture recognizer.
ImageLabelControl.xaml
<ContentView.Content>
<StackLayout x:Name="Container"
HorizontalOptions="FillAndExpand">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer x:Name="Recognizer" Tapped="Recognizer_OnTapped" />
</StackLayout.GestureRecognizers>
<Image x:Name="ImageCell" />
<Label x:Name="LabelCell" />
</StackLayout>
</ContentView.Content>
ImageLabelControl.xaml.cs
...
private void Recognizer_OnTapped(object sender, EventArgs e)
{
//ExecuteIfPossible just checks if the CanExecute of the ICommand returns true
Command?.ExecuteIfPossible(CommandParameter);
}
...
when i use the above control on a ListView the ItemTapped Event when running on Android never gets fired. On UWP the event gets fired as expected.
ListView Test Case:
<ListView ItemsSource="{Binding DropdownOptionsCommands}">
<ListView.Behaviors>
<behaviors:EventToCommandBehavior
EventName="ItemTapped"
Command="{Binding ExecuteDropdownCommand}" />
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<controls:ImageLabelControl WidthRequest="200"
Orientation="Horizontal"
ImageSource="{Binding ImageUrl,Converter={StaticResource ImageConverter}}"
ImageHeightRequest="30"
ImageMargin="20,5,20,5"
ImageVerticalOptions="Center"
Text="{Binding Text}"
LabelMargin="20,5,20,5"
VerticalTextAlignment="Center"
LabelVerticalOptions="Center"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Implementation of EventToCommandBehavior on github
ExecuteDropdownCommand
if (!(e is ItemTappedEventArgs ev)) return;
if (!(ev.Item is OptionCommands comm)) return;
if (comm.Command == null) return;
comm.Command.ExecuteIfPossible(comm.CommandParameter);
DropdownOptionsCommands is an ObservableCollection of OptionCommands
public class OptionCommands
{
public string ImageUrl { get; set; }
public string Text { get; set; }
public ICommand Command { get; set; }
public object CommandParameter { get; set; }
public OptionCommands()
{ }
public OptionCommands(string text, ICommand command, object parameter = null)
{
Text = text;
Command = command;
CommandParameter = parameter;
}
public OptionCommands(string imageUrl, string text,
ICommand command, object parameter = null) : this(text, command, parameter)
{
ImageUrl = imageUrl;
}
If you need more info please leave a comment.
Thank you.
I would try to put a background colour to the ListView! Sounds like a similar problem:
https://forums.xamarin.com/discussion/99978/different-tap-handling-in-android-and-uwp
Just posted it as an answer, it could help someone someday.

Categories