XAML、绑定、源和路径

XAML, Binding, Source and Path

我正在学习了解绑定机制在 XAML for .NET MAUI 中的工作原理。我假设这对所有 XAML 项目、WPF、MAUI 等都是一样的

最后是整个XAML.

这个XAML工作正常:

<Button WidthRequest="150" Text="Add Activity" 
                Command="{Binding AddActivityEntityCommand}"
                IsEnabled="{Binding IsNotBusy}"
                Grid.Row="2"
                Margin="8"/>

另一方面,这并不像开箱即用那样简单:

<Label HorizontalOptions="End" TextColor="Red" Padding="0,0,10,0" Text="" 
       IsVisible="{Binding IsSynchronized}">
            <Label.GestureRecognizers>
                 <TapGestureRecognizer 
                       Command="{Binding Source={x:Type viewmodel:MainPageViewModel},
                                            Path=DeleteActivityCommand}" />
            </Label.GestureRecognizers>
 </Label>

System.Reflection.TargetException: Object does not match target type.

我错过了什么?

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="OnesieMobile.View.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:model="clr-namespace:OnesieMobile.Model"
    xmlns:viewmodel="clr-namespace:OnesieMobile.ViewModel"
    x:DataType="viewmodel:MainPageViewModel"
    Title="{Binding Title}">
    <Grid
        ColumnDefinitions="*"
        RowDefinitions="20,50,50,*"
        RowSpacing="0">
        <Label HorizontalOptions="End" Margin="10,0,10,0"  Text="{Binding CurrentDateTime}" Grid.Row="0"/>
        <Entry Margin="10,0,10,0" 
            Grid.Row="1"  x:Name="entryNewActivity" 
            Placeholder="New Activityssss" HeightRequest="30" Text="{Binding NewActivityTitle}" />

        <Button WidthRequest="150" Text="Add Activity" 
                    Command="{Binding AddActivityEntityCommand}"
                    IsEnabled="{Binding IsNotBusy}"
                    Grid.Row="2"
                    Margin="8"/>

        <CollectionView
            Grid.Row="3"
                ItemsSource="{Binding ActivityEntities}"
                SelectionMode="None">
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="model:ActivityEntity">
                    <Grid Padding="10,0,10,0">
                        <Frame Style="{StaticResource CardView}">
                            <Grid  ColumnDefinitions="*,30,50">
                                <StackLayout Padding="10,5,0,0" Grid.Column="0">
                                    <Label Text="{Binding Title}"  />
                                </StackLayout>
                                <StackLayout Padding="10,5,0,0" Grid.Column="1">
                                    <Label HorizontalOptions="End" TextColor="Red"
                                           Padding="0,0,10,0" Text="" IsVisible="{Binding IsSynchronized}"  >
                                        <Label.GestureRecognizers>
                                            <TapGestureRecognizer
                                                Command="{Binding Source={x:Type viewmodel:MainPageViewModel},
                                                Path=DeleteActivityCommand}" />
                                        </Label.GestureRecognizers>
                                    </Label>
                                </StackLayout>
                                <StackLayout Padding="10,5,0,0" Grid.Column="2">
                                    <Label HorizontalOptions="End" 
                                           Padding="0,0,10,0" Text="✔" IsVisible="{Binding IsSynchronized}"  />
                                </StackLayout>
                            </Grid>
                        </Frame>
                    </Grid>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
        <ActivityIndicator IsVisible="{Binding IsBusy}"
                               IsRunning="{Binding IsBusy}"
                               HorizontalOptions="FillAndExpand"
                               VerticalOptions="CenterAndExpand"
                               Grid.RowSpan="3"
                               Grid.ColumnSpan="2"/>

    </Grid>
</ContentPage>

更新:
MainPageViewModel.cs 包含这些命令

[ICommand]
async Task DeleteActivityAsync()
{
}


[ICommand]
async Task AddActivityEntityAsync()
{
}

在项目模板中,有几种方法可以引用原始的 BindingContext。我喜欢通过从集合本身获取它来做到这一点:

<CollectionView x:Name="myCollection" ...>
    ...
    <CollectionView.ItemTemplate>
        ...
        Command="{Binding Source={x:Reference myCollection},
                  Path=BindingContext.DeleteActivityCommand}" />

未来待定:

我不喜欢执行代码中任何地方都不存在的命令名称。希望最终会有一种方法可以在 ICommand 属性中 指定 命令名称,使其显而易见:

// This won't work today.
[ICommand Name="DeleteActivityCommand"]
...

现在,我们必须学习 [ICommand] 的神奇命名规则,这似乎是“从末尾删除 Async(如果存在);将 Command 添加到末尾” .