7

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) {}
jbdev
  • 373
  • 2
  • 15
  • 1
    I'm not sure an event can be bound. It's way cleaner the method you're using, binding `SelectedIndex`. You can simply change the second picker items when the property bound to `SelectedIndex` changes. – Riccardo Minato Jun 09 '22 at 14:53
  • 2
    You bind commands, not events. At a glance, the docs don't indicate that the MAUI Picker supports any commands. You can use EventToCommand behaviors to get around this, or just have event handlers in your code behind call the corresponding VM method, or do as @RiccardoMinato suggests – Jason Jun 09 '22 at 14:54
  • Thanks @RiccardoMinato and @Jason, I think I will change the second picker when ```SelectedIndex``` changes. I am using the MVVM CommunityToolkit, so I will have to figure out the correct way to do that. Should be trivial. – jbdev Jun 09 '22 at 15:08

1 Answers1

4

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

Riccardo Minato
  • 520
  • 2
  • 11
  • I added the partial method to the viewmodel and get an error saying, "No defining declaration found for implementing delcaration of partial method...". I will update my question with my code. – jbdev Jun 09 '22 at 15:43
  • Do I need CommunityToolkit.Mvvm preview version 8 for this functionality? – jbdev Jun 09 '22 at 16:11
  • 1
    @JBest exactly, try using the latest preview version – Riccardo Minato Jun 09 '22 at 16:13
  • 1
    Thanks, this worked. I'm getting ambiguity warnings when referencing the public ```ObservableProperties``` in the viewmodel now, but that's outside the scope of this question I think. I will mark this as correct answer. – jbdev Jun 09 '22 at 16:29
  • 3
    @JBest Can you show your code perhaps as I'm having the same issue of getting at the picker SelectionIndexChanged from my ViewModel. Man why didn't they just implement a Command as with other Views! – gfmoore Jun 21 '22 at 18:29
  • @gfmoore I've added the code as "Update 2". The ViewModel responds to the changed property bound to the index, so there's no commands or events in the code-behind in this solution. – jbdev Jun 21 '22 at 19:50
  • 1
    Wonderful. For others: IMPORTANT Don't miss it like I did - Use "CommunityToolkit.Mvvm" Version="8.0.0-preview4" :() Thanks so much. – gfmoore Jun 22 '22 at 08:44