I am trying to bind the ItemSelected of a ListView to a View Model, but am experiencing some issues (due to my own misunderstands around how it all works).
I have view:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Local="clr-namespace:FireLearn.ViewModels"
x:Class="FireLearn.MainPage"
Title="Categories">
<ContentPage.BindingContext>
<Local:CategoryViewModel/>
</ContentPage.BindingContext>
<NavigationPage.TitleView>
<Label Text="Home"/>
</NavigationPage.TitleView>
<ListView
ItemsSource="{Binding Categories}"
HasUnevenRows="True"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding ListRefreshing, Mode=OneWay}"
RefreshCommand="{Binding RefreshCommand}"
ItemSelected="{Binding OnItemTappedChanged}"
SelectionMode="Single"
SelectedItem="{Binding SelectedCategory}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<HorizontalStackLayout
Padding="8"
VerticalOptions="Fill"
HorizontalOptions="Fill">
<Image Source="cafs_bubbles.png"
HeightRequest="64"
MaximumWidthRequest="64"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/>
<VerticalStackLayout
Padding="8"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<Label Text="{Binding FormattedName}"
SemanticProperties.HeadingLevel="Level1"
FontSize="Title"
HorizontalOptions="Start"/>
<Label Text="{Binding ItemCount}"
FontSize="Subtitle"/>
<Label Text="{Binding Description}"
HorizontalOptions="Center"
LineBreakMode="WordWrap"
FontSize="Caption"
VerticalOptions="CenterAndExpand"
MaxLines="0"/>
</VerticalStackLayout>
</HorizontalStackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
This is linked to a view model:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FireLearn.Models;
namespace FireLearn.ViewModels
{
public partial class CategoryViewModel : ObservableObject
{
public ObservableCollection<CategoryModel> categories = new ObservableCollection<CategoryModel>();
public ObservableCollection<CategoryModel> Categories
{
get => categories;
set => SetProperty(ref categories, value);
}
public bool listRefreshing = false;
public bool ListRefreshing
{
get => listRefreshing;
set => SetProperty(ref listRefreshing, value);
}
public CategoryModel selectedCategory = new CategoryModel();
public CategoryModel SelectedCategory
{
get => selectedCategory;
set
{
SetProperty(ref selectedCategory, value);
// Tap(value);
}
}
public RelayCommand RefreshCommand { get; set; }
//public RelayCommand TapCellCommand { get; set; }
public CategoryViewModel()
{
loadFromSource();
RefreshCommand = new RelayCommand(async () =>
{
Debug.WriteLine($"STARTED::{ListRefreshing}");
if (!ListRefreshing)
{
ListRefreshing = true;
try
{
await loadFromSource();
}
finally
{
ListRefreshing = false;
Debug.WriteLine($"DONE::{ListRefreshing}");
}
}
});
}
public async Task loadFromSource()
{
HttpClient httpClient = new()
{
Timeout = new TimeSpan(0, 0, 10)
};
Uri uri = new Uri("https://somewebsite.co.uk/wp-json/wp/v2/categories");
HttpResponseMessage msg = await httpClient.GetAsync(uri);
if (msg.IsSuccessStatusCode)
{
var result = CategoryModel.FromJson(await msg.Content.ReadAsStringAsync());
Categories = new ObservableCollection<CategoryModel>(result);
}
Debug.WriteLine("List Refreshed");
}
public void OnItemTappedChanged(System.Object sender, Microsoft.Maui.Controls.SelectedItemChangedEventArgs e)
{
var x = new ShellNavigationState();
Shell.Current.GoToAsync(nameof(NewPage1),
new Dictionary<string, object>
{
{
nameof(NewPage1),
SelectedCategory
}
});
}
}
}
I get compiler error "No property, BindableProperty, or event found for "ItemSelected", or mismatching type between value and property" and am really unsure of how to resolve. If I let XAML create a new event for me, it adds it in MainPage.Xaml.Cs rather than the VM
ItemSelected
expects an event handler defined in the code behind of your View (the .xaml.cs file). Where isOnItemTappedChanged
defined? You're trying to use a binding, which won't work for that, event handlers usually exist in the code behind only. You should use Commands in the ViewModel. Please show your code behind, add it to the question. By the way, you should make the backing fields of your propertiesprivate
. – PeepholeItemSelected
is an event. You can't bind a command to an event. You can't bind anything to an event. You can useEventToCommandBehavior
as a workaround for this, or just have the event handler in your code behind call the VM command. – Forseti