xamarin-forms-samples
xamarin-forms-samples copied to clipboard
Complex Control Template Sample Request
I would like to see a sample application with the following:
- You have a ViewModel and an associated Page
- The ViewModel instance is set to the BindingContext inside the Page's code-behind using Microsoft.Extensions.DependencyInjection, e.g. in the contructor, you set
BindingContext = Startup.ServiceProvider.GetService<MyViewModel>(); - The Page uses a ControlTemplate, and references a subview (i.e. ContentView instance) that uses a separate XAML and codebehind.
- The ViewModel instance contains an ObservableCollection that is displayed in the subview using a ListView. The ItemSource is set to the ObservableCollection in the ViewModel using TemplateBinding. An item inside this ObservableCollection is of type
MyViewModelItem. - ViewCell.ContextActions is applied to the ListView, and a MenuItem is created in order to delete an item in the ObservableCollection. Using the Command property of the MenuItem, this will bind to a Command that is defined in the initial ViewModel.
I have attempted to create this myself, but I've given up due to difficulties with data binding debugging.
<!-- This doesn't work -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={RelativeSource TemplatedParent}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference Name=MyPage}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference Name=MyView}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{TemplateBinding Path=BindingContext.DeleteCommand}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={RelativeSource Mode=TemplatedParent}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type sample:MyPage}}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- <MenuItem Command="{Binding Path=BindingContext.DeleteCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type vm:MyViewModel}}}" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" /> -->
<!-- This works! -->
<MenuItem Clicked="OnDeleteClicked" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" />
Instead I opted for an alternative solution where I used the subview's codebehind to reference the parent's BindingContext (i.e. ViewModel instance).
public void OnDeleteClicked (object sender, EventArgs e)
{
var mi = ((MenuItem)sender);
MyViewModelItem item = (MyViewModelItem)mi.CommandParameter;
MyViewModel vm = ((MyViewModel)this.Parent.BindingContext);
vm.DeleteCommand.Execute(item);
}
This is not a preferred solution IMHO, but I can't reallly spend any more time on debugging this.