Reputation: 1429
I have the following XAML
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:LogEntry">
<SwipeView>
<SwipeView.RightItems>
<SwipeItem Text="Delete"
BackgroundColor="Orange"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewModel:MainPageViewModel}}, Path=RemoveLogEntryCommand}"
CommandParameter="{Binding .}" />
<SwipeItem Text="Delete"
BackgroundColor="Red"
IsDestructive="True" />
</SwipeView.RightItems>
<Grid Padding="10">
<Frame HeightRequest="125"
Padding="0"
Style="{StaticResource CardView}">
<Frame.GestureRecognizers>
<TapGestureRecognizer CommandParameter="{Binding .}"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewModel:MainPageViewModel}}, Path=GotoLogEntryDetailsCommand}" />
</Frame.GestureRecognizers>
<Grid Padding="0"
ColumnDefinitions="80,*">
with the following ICommand declarations using the community toolkit
[RelayCommand]
private async Task GotoLogEntryDetails(LogEntry logEntry)
{
if (logEntry == null)
return;
await _appNavigationService.GoTo($"{nameof(LogEntryDetailsPage)}", true,
new Dictionary<string, object>
{
{ "LogEntry", logEntry }
});
}
[RelayCommand]
private async Task RemoveLogEntry(LogEntry logEntry)
{
}
If I put a breakpoint in RemoveLogEntry
then click my delete button the breakpoint is never reached. If I put RemoveLogEntry
on the tap gesture and tap am item then the breakpoint is reached, so I know that the code generator has created a valid ICommand.
Intellisense tells me that the argument on CommandParameter .
is actually a LogEntry therefore I need to declare the viewModel type.
What is wrong with the SwipeItem's ancestor binding path?
Upvotes: 3
Views: 2457
Reputation: 28
I can confirm that the Command Attribute in SwipeItem does not work without a SwipeItems Object as Parent.
This Binding hase worked for me:
<SwipeItems>
<SwipeItem
IconImageSource="delete.png"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:TagListDetailViewModel}},Path=DeleteTagCommand}"
CommandParameter="{Binding .}"/>
</SwipeItems>
Upvotes: 1
Reputation: 11
A late answer to this. But I had the same issue with the ancestor method and I fixed it by surrounding the swipeItem with SwipeItems
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="Orange"
Command="{Binding Source={RelativeSource AncestorType={x:Type viewModel:MainPageViewModel}}, Path=RemoveLogEntryCommand}"
CommandParameter="{Binding .}" />
<SwipeItem Text="Delete"
BackgroundColor="Red"
IsDestructive="True" />
</SwipeItems>
</SwipeView.RightItems>
Upvotes: 1
Reputation: 21321
UPDATE
The first part of this answer ("Views vs Viewmodels") might be an incorrect explanation of the problem. I've seen this "viewmodel reference" syntax several places. Have not taken the time to test how/when it works. Regardless, referring to "View" ancestor always works. As does the "Alternative syntax" approach.
VIEWS vs VIEWMODELS
UI elements (views) and viewmodels are in DIFFERENT hierarchies. A viewmodel is NEVER an ancestor of a view. So you can't find such an ancestor.
VIEW Ancestor
Instead, find the VIEW that is the ancestor. That view's BindingContext
will be the corresponding viewmodel.
Change:
<SwipeItem ... Command="{Binding Source={RelativeSource AncestorType={x:Type viewModel:MainPageViewModel}}, Path=RemoveLogEntryCommand}"
To:
<SwipeItem ... Command="{Binding Source={RelativeSource AncestorType={x:Type MainPageView}}, Path=BindingContext.RemoveLogEntryCommand}"
ALTERNATIVE SYNTAX
However, I never use that syntax. I find it easier to give an x:Name
to the element I want to refer to. Then can use a simple x:Reference
Source:
<ContentPage
...
x:Name="thisPage">
...
<SwipeItem ... Command={Binding BindingContext.RemoveLogEntryCommand, Source={x:Reference thisPage}"
Upvotes: 4