Search code examples
c#xamlmvvmdata-bindingmaui

.NET Maui MVVM Picker Binding SelectedIndexChanged Event


I am developing a Windows desktop app with .NET Maui using MVVM.

I have 2 Pickers with ImageSource and SelectedIndex bound to properties in a viewmodel. When an item is selected from the first Picker the items in the other need to be changed. I would like to bind the SelectedIndexChanged event to a method in the viewmodel to accomplish this.

The XAML for the event in the picker Picker looks like this:

<Picker SelectedIndexChanged="{Binding OnSelectedIndexChanged}" />

The method in the viewmodel looks like this:

public void OnSelectedIndexChanged(object sender, EventArgs e)
{
    // do stuff
}

But I get the following error when running the program:

XFC0009 No property, BindableProperty, or event found for "SelectedIndexChanged", or mismatching type between value and property. MauiApp1

My temporary solution is to call the viewmodel method from the code behind when the event fires. The code behind looks like this:

private void Picker_SelectedIndexChanged(object sender, EventArgs e)
{
    (BindingContext as MainViewModel).OnSelectedIndexChanged(sender, e);
}

I would like to keep the code behind as dumb as possible. Is there a way to handle the SelectedIndexChanged event by binding directly to a method in the viewmodel?

Update Trying to implement partial void On<PropertyName>Changed()

My viewmodel:

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<ProductGroupRoot> itemSourceProductGroups = new();

    [ObservableProperty]
    private int selectedProductGroup = -1;

    [ObservableProperty]
    private ObservableCollection<ProductRoot> itemSourceProducts = new();

    [ObservableProperty]
    private int selectedProduct = -1;
    
    // other properties

    partial void OnSelectedProductGroupChanged(int value)
    {
        // TODO: change values in ItemSourceProducts
    }        
}

The autogenerated code should have created a definition for the partial method, but I get the error:

CS0759 No defining declaration found for implementing declaration of partial method 'MainViewModel.OnSelectedProductGroupChanged(int)'

I am using CommunityToolkit.Mvvm v7.1.2 (latest stable).

Update 2 Posting the working code.

My csproj file:

<Project>
    <ItemGroup>
        <PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0-preview4" />
    </ItemGroup>
</Project>

My Picker:

<Picker ItemsSource="{Binding ProductGroups, Mode=TwoWay}" 
        SelectedIndex="{Binding ProductGroupsIndex, Mode=TwoWay}" />

My ViewModel:

[ObservableProperty]
private ObservableCollection<ProductGroupRoot> productGroups = new();

[ObservableProperty]
private int productGroupsIndex = -1;

partial void OnProductGroupsIndexChanged(int value) {}

Solution

  • You can simply change the second picker items when the property bound to SelectedIndex changes.

    Since you're using MVVM CommunityToolkit, to execute some code after a property changed, you have to implement a partial method which is defined in the autogenerated class. This method is called On<YourPropertyName>Changed().

    To be noticed that this feature is available only since version 8.0.0.

    Check this answer: https://stackoverflow.com/a/72499605/7977288