xamarin-forms-samples icon indicating copy to clipboard operation
xamarin-forms-samples copied to clipboard

Complex Control Template Sample Request

Open v3gard opened this issue 4 years ago • 0 comments

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.

v3gard avatar Mar 05 '21 10:03 v3gard