我有一个 ContentView,其中包含一个 CollectionView。
...
xmlns:templates="clr-namespace:PropertyManagement.Portfolio.DataTemplates"
xmlns:vm="clr-namespace:PropertyManagement.Portfolio.ContentViews.ViewModels"
x:Class="PropertyManagement.Portfolio.ContentViews.AgreementListView">
<ScrollView>
<CollectionView x:DataType="vm:AgreementListVM" x:Name="MyCollectionView" ItemsSource="{Binding AllAgreements}" Margin="10,0">
<CollectionView.ItemTemplate>
<DataTemplate>
<templates:AgreementListViewDataTemplate />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
DataTemplate 包含一些数据绑定标签和一个 ImageButton
<Border
x:Class="PropertyManagement.Portfolio.DataTemplates.AgreementListViewDataTemplate"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:models="clr-namespace:PropertyManagement.Portfolio.Models"
xmlns:vm="clr-namespace:PropertyManagement.Portfolio.ContentViews.ViewModels"
x:DataType="models:Agreement">
<VerticalStackLayout HorizontalOptions="Start" Padding="10">
<HorizontalStackLayout HorizontalOptions="Start" Spacing="10">
<Label FontAttributes="Bold" Text="{Binding Name}" />
<Label FontAttributes="Bold" Text="{Binding Tenant.FirstName}" />
<Label FontAttributes="Bold" Text="{Binding LetProperty.Address1}" />
<ImageButton
Source="edit.png"
WidthRequest="15" />
</HorizontalStackLayout>
</VerticalStackLayout>
</Border>
这一切都很好。
现在我想将图像按钮命令绑定到位于父ContentViews视图模型(即AgreementListVM)中的ICommand(使用CommunityToolkit的RelayCommand)。 如果我使用
Command="{Binding Source={vm:AgreementListVM}, Path=EditAgreementCommand}"
那么它就可以正常工作,但这需要 DataTemplate 了解父视图的 ViewModel。我希望数据模板可以在不依赖于知道要使用的视图模型的情况下使用。
我已经尝试过了
Command="{Binding EditAgreementCommand, Source={RelativeSource AncestorType={x:Type vm:AgreementListVM}}}"
如此处所述[ https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/relative-bindings?view=net-maui-8.0#bind-to-an-ancestor ]
它不起作用,没有绑定失败只是不会触发中继命令,并且仍然需要知道要使用的 viemodel。
我已经尝试过了
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:AgreementListVM}}, Path=EditAgreementCommand}"
项目编译并运行,智能感知甚至知道它是 IRelayCommand,但该命令不会触发,并且仍然需要了解视图模型。我想知道为什么当工作代码看起来简单得多时我会使用这些?
尝试过这个,这正是我想要的!
Command="{Binding Source={x:Reference MyCollectionView}, Path=BindingContext.EditAgreementCommand}"
如此处所述 [https://github.com/dotnet/maui/discussions/17771]
编译并运行,但绑定失败
在“Microsoft.Maui.Controls.Xaml.ReferenceExtension”上找不到“BindingContext”属性,目标属性:“Microsoft.Maui.Controls.ImageButton.Command”C:\Users\kev12\OneDrive\Documents\Current Projects\MAUI\PropertyManagement \Portfolio\DataTemplates\AgreementListViewDataTemplate.xaml。
我的头在里面!!有人可以指出我做错了什么吗?
PS 如果我在后面的代码中分配内容视图视图模型,则不会更改任何内容
public AgreementListView()
{
InitializeComponent();
BindingContext = new AgreementListVM();
}
您可以尝试以下代码:
文件结构如下:
模型/NameId.cs:
public class NameId
{
public string Name { get; set; }
public string Id { get; set; }
}
ViewModels/BaseViewModel.cs:
public class BaseViewModel
{
public ObservableCollection<NameId> NameIdList { get; set; }
public ICommand AddCharCommand { get; private set; }
public BaseViewModel()
{
NameIdList = new ObservableCollection<NameId>
{
new NameId { Id = "Id A", Name = "Name A" },
new NameId { Id = "Id B", Name = "Name B" },
new NameId { Id = "Id C", Name = "Name C" }
};
AddCharCommand = new Command(Addc);
}
private void Addc(object obj)
{
Console.WriteLine("click");
}
}
数据模板/CardViews.cs:
public class CardView : ContentView
{
public static readonly BindableProperty NameProperty =
BindableProperty.Create(nameof(Name), typeof(string), typeof(CardView), string.Empty);
public static readonly BindableProperty IDProperty =
BindableProperty.Create(nameof(ID), typeof(string), typeof(CardView), string.Empty);
public string Name
{
get => (string)GetValue(NameProperty);
set => SetValue(NameProperty, value);
}
public string ID
{
get => (string)GetValue(IDProperty);
set => SetValue(IDProperty, value);
}
}
在App.xaml中创建ControlTemplate:
<Application ...
xmlns:m="clr-namespace:MauiApp5.Models"
xmlns:vm="clr-namespace:MauiApp5.ViewModels"
xmlns:local="clr-namespace:MauiApp5"
x:Class="MauiApp5.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
....
</ResourceDictionary.MergedDictionaries>
<ControlTemplate x:Key="AgreementListViewControlTemplate">
<VerticalStackLayout HorizontalOptions="Start" Padding="10" BindingContext="{Binding Source={RelativeSource TemplatedParent}}">
<HorizontalStackLayout HorizontalOptions="Start" Spacing="10">
<Label FontAttributes="Bold" Text="{Binding Name}" />
<Label FontAttributes="Bold" Text="{Binding ID}" />
<ImageButton
Source="kb.png"
Aspect="AspectFill"
WidthRequest="50" HeightRequest="50"
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:BaseViewModel}}, Path=AddCharCommand}"/>
</HorizontalStackLayout>
</VerticalStackLayout>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
在特定页面消费
AgreementListViewControlTemplate
:
<ContentPage ...
xmlns:vm="clr-namespace:MauiApp5.ViewModels"
xmlns:m="clr-namespace:MauiApp5.Models"
xmlns:templates="clr-namespace:MauiApp5.DataTemplates"
x:Class="MauiApp5.NewPage1"
Title="NewPage1">
<ContentPage.BindingContext>
<vm:BaseViewModel/>
</ContentPage.BindingContext>
<VerticalStackLayout>
<CollectionView ItemsSource="{Binding NameIdList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<templates:CardView Name="{Binding Name}"
ID="{Binding Id}"
ControlTemplate="{StaticResource AgreementListViewControlTemplate}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ContentPage>