.NET MAUI EventToCommandBehavior - Operation is not valid due to the current state of the object

388 Views Asked by At

I have a bound CollectionView on my page that contains ImageButton controls for each record. I'm trying to add a handler for the Clicked event that passes a parameter to the Command. Due to the fact that the CollectionView has it's own DataTemplate/DataType I believe I have to use the RelativeSource option on the Binding of the Command.

As soon as the CollectionView loads, I get a nasty unhandled exception at the App level (Operation is not valid due to the current state of the object.)

enter image description here

I've tried it with every one of the Modes.

I've tried the Path as just PdfViewCommand, BindingContext.PdfViewCommand and as it is below.

I've also tried it without the parameter at all with no change in behavior.

Please note, the exception pops before the RelayCommand is even hit.

<CollectionView.ItemTemplate>
    <DataTemplate x:DataType="model:PatientEd">
        <VerticalStackLayout BackgroundColor="Transparent" Margin="2" >
            <ImageButton Source="{Binding PatientEdThumbUri}" HeightRequest="85" Margin="2" CornerRadius="10" HorizontalOptions="Center" BorderColor="White" BorderWidth="2" ToolTipProperties.Text="{Binding PatientEdName}">
                <ImageButton.Behaviors>
                    <toolkit:EventToCommandBehavior
                        EventName="Clicked"
                        Command="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type viewmodel:PatientEdViewModel}}, Path=PatientEdViewModel.PdfViewCommand}"
                        CommandParameter="{Binding PatientEdPdfUri}" />        
                </ImageButton.Behaviors>
            </ImageButton>
            
            <Label Text="{Binding PatientEdName}" HorizontalTextAlignment="Center" FontSize="Caption" HeightRequest="30" WidthRequest="100" HorizontalOptions="Center" />
        </VerticalStackLayout>
    </DataTemplate>
</CollectionView.ItemTemplate>

UPDATE: I found this stack trace from the e argument of the UnhandledException call, doesn't mean much tome...

at Microsoft.Maui.Controls.Binding.d__27.MoveNext() at System.Threading.Tasks.Task.<>c.b__128_0(Object state) at Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext.<>c__DisplayClass2_0.b__0()

UPDATE: Now that the CollectionView is loading without the exception, clicking on any ImageButton has no effect. My Command is set up differently than your example. Mine is asynchronous and I use the [RelayCommand] decoration.

[RelayCommand]
async Task PdfViewAsync(Object obj)
{
    if (IsBusy)
        return;

    try
    {
        IsBusy = true;

        var model = obj as PatientEd;

        // Do stuff

    }
    catch (Exception ex)
    {
        Debug.WriteLine($"Unable to get Patient titles: {ex.Message}");
        await Shell.Current.DisplayAlert("Error!", ex.Message, "OK");
    }
    finally
    {
        IsBusy = false;
    }

}

I use this arrangement for other handlers (for Pickers) and it works great. It this arrangement different for an ImageButton? I've got a breakpoint at the top of the method and it doesn't get hit when I click on one of the buttons. Thoughts?

1

There are 1 best solutions below

3
On BEST ANSWER

You can pass the whole item of the CollectionView as the parameter of command PdfViewCommand to your ViewModel.

Please refer to the following code:

                        <ImageButton Source="{Binding PatientEdThumbUri}"  Grid.Column="2" HeightRequest="60" WidthRequest="60"   BackgroundColor="Yellow"  >
                            <ImageButton.Behaviors>
                                <toolkit:EventToCommandBehavior
                                  EventName="Clicked"
                                  Command="{Binding Source={x:Reference myCollectionView}, Path=BindingContext.PdfViewCommand}"
                                  CommandParameter="{Binding .}" />
                            </ImageButton.Behaviors>
                        </ImageButton>

Note:

myCollectionView is the x:Name of your collectionView.

Then we can get the passed parameter as follows:

    public ICommand PdfViewCommand => new Command<PatientEd>(DoSomething);

    private void DoSomething(PatientEd obj)
    {
        System.Diagnostics.Debug.WriteLine("---------> "+obj.PatientEdPdfUri);
    }