I'm fighting with bindings in a CollectionView, enough time wasted!
The data model class is called Event. An ObservableCollection of these is bound to the CV.
I am trying hard to stick to MVVM so I want to use EventToCommandBehavior to keep everything in the view model.
Here is the xaml and VM code:
<?xml version="1.0" encoding="utf-8" ?>
<toolkit:Popup xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:local="clr-namespace:My.Namespace.MyApp"
xmlns:models="clr-namespace:My.Namespace.MyApp.Models"
xmlns:views="clr-namespace:My.Namespace.MyApp.Views"
xmlns:vm="clr-namespace:My.Namespace.MyApp.ViewModels"
x:Class="views:EditorPopup"
x:DataType="vm:EditorPopupViewModel"
x:Name="ThisPopup">
<CollectionView ItemsSource="{Binding DataProvider.Events}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Event">
<ContentView>
<Grid>
<Switch IsToggled="{Binding IsEnabled}">
<Switch.Behaviors>
<toolkit:EventToCommandBehavior
EventName="Toggled"
BindingContext="{Binding Source={x:Reference ThisPopup}}"
Command="{Binding BindingContext.ToggleEventCommand, Source={x:Reference ThisPopup}, x:DataType=vm:EventsEditorPopupViewModel}"
CommandParameter="{Binding}" />
</Switch.Behaviors>
</Switch>
</Grid>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</toolkit:Popup>
[RelayCommand]
private async Task ToggleEventAsync(Event eventData)
{
if (eventData != null
&& GetEventById(eventData.Id) is Event e)
{
await DataProvider.ToggleAsync(e.Id);
await DataProvider.SaveAsync();
}
}
I am getting these binding failures in VS:
Mismatch between the specified x:DataType (My.Namespace.MyApp.Models.Event) and the current binding context (My.Namespace.MyApp.Views.EditorPopup).
Mismatch between the specified x:DataType (My.Namespace.MyApp.ViewModels.EditorPopupViewModel) and the current binding context (My.Namespace.MyApp.Views.EditorPopup).
My intention is to get the VM from the popup (ThisPopup), so that I can then reference the Command method, and pass the bound item as the parameter.
For your EventToCommandBehavior it appears you need access to:
ThisPopup typed as views:EditorPopupThisPopup.BindingContext type as vm:EventsEditorPopupViewModelcontentView.BindingContext (i.e. DataTemplate's BindingContext)To do this, I would need to:
ContentView an x:Name, say "contentView"BindingContext of the EventToCommandBehavior to ThisPopup.BindingContextEventToCommandBehavior know that the new BindingContext is vm:EventsEditorPopupViewModelCommand propertyCommandParameter binding since the BindingContext is no longer the DataTemplate so we use the ContentView.BindingContext to regain access to the DataTemplate's BindingContext.<ContentView x:Name="contentView">
<Grid>
<Switch IsToggled="{Binding IsEnabled}">
<Switch.Behaviors>
<toolkit:EventToCommandBehavior
EventName="Toggled"
BindingContext="{Binding BindingContext, Source={Reference ThisPopup}, x:DataType='views:EditorPopup'}"
x:DataType="vm:EventsEditorPopupViewModel"
Command="{Binding ToggleEventCommand}"
CommandParameter="{Binding BindingContext, Source={Reference contentView}, x:DataType='ContentView'}" />
Generally the rules I follow are:
x:DataType for every Binding to Source, e.g."{Binding Path=anything, Source={Reference xyz}, x:DataType='type_of_xyz'}"
x:DataType for every BindingContext change, e.g.<AnyComponent
BindingContext="change_to_anything_here"
x:DataType="type_of_BindingContext" />