我正在学习理解。net MAUI的XAML绑定机制是如何工作的。我假设这对于所有XAML项目,WPF, MAUI等都是相同的。
最后是整个XAML。
这个XAML工作得很好:
<Button WidthRequest="150" Text="Add Activity"
Command="{Binding AddActivityEntityCommand}"
IsEnabled="{Binding IsNotBusy}"
Grid.Row="2"
Margin="8"/>
这是因为按钮是ContentPage的一部分,它的
x:DataType
设置为MainPageViewModel
,这是命令生活的地方吗?绑定设置为
AddActivityEntityCommand
,实际方法签名为async Task AddActivityEntityAsync()
。如何解决这个问题?因为它显然与名字不匹配,但它有效。要使其工作/被识别,方法签名要求是什么?
另一方面,这并不像开箱即用那样容易:
<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>
- 在这种情况下,添加
Command="{Binding DeleteActivityCommand}
不起作用,因为它从<DataTemplate x:DataType="model:ActivityEntity">
派生其路径,我假设,这是数据对象而不是ViewModel,命令实际上在哪里。 - 这里的问题是,只要我进入这个XAML
Command="{Binding Source={x:Type viewmodel:MainPageViewModel}, Path=DeleteActivityCommand}"
, CollectionView显示为空,并且在加载视图时抛出一个未处理的异常:
System.Reflection。TargetException: Object does not match target type.
- 此命令的方法签名为
async Task DeleteActivityAsync()
我错过了什么?
<?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}" />
未来TBD:我不喜欢命令名在实现代码的任何地方都不存在。希望最终会有一种方法可以在ICommand属性中指定命令名称,以使其明显:
// This won't work today.
[ICommand Name="DeleteActivityCommand"]
...
现在,我们必须学习[ICommand]
的神奇命名规则,它似乎是"从结束删除Async
(如果存在);将Command
添加到end"