如何让CollectionView内按钮触发ViewModel的ICommand(EditProduct方法)
问题描述
在使用Mvvm.Toolkit的MAUI应用中,CollectionView内的按钮点击无法触发ViewModel中的EditProduct命令,但相同实现逻辑在其他ViewModel中正常工作,应用其他功能无异常。
相关代码
ViewModel代码
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace ShoppingCart.Models { public partial class ProductViewModel : ObservableObject { public ObservableCollection<Product> Products {get; set; } = new ObservableCollection<Product>(); [ObservableProperty] public string productId; [ObservableProperty] public string productName; [ObservableProperty] public string description; [ObservableProperty] public string imageUrl; [ObservableProperty] public int quantity; [ObservableProperty] public int price; public ProductViewModel() { GetAllProducts(); } [ICommand] public void EditProduct() { App.Current.MainPage.DisplayAlert("Hello", "sdfs", "Ok"); } public void GetAllProducts() { var client = new HttpClient(); string url = "https://834xqncj-7275.inc1.devtunnels.ms/api/Product/Index"; client.BaseAddress = new Uri(url); HttpResponseMessage response = client.GetAsync(client.BaseAddress).Result; if (response.IsSuccessStatusCode) { string content = response.Content.ReadAsStringAsync().Result; List<Product> products = JsonConvert.DeserializeObject<List<Product>>(content); Products = new ObservableCollection<Product>(products); } } } }
XAML代码
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:ShoppingCart.Models" x:DataType="vm:ProductViewModel" x:Class="ShoppingCart.Pages.AdminPage" Title="AdminPage"> <VerticalStackLayout> <Button x:Name="AddBtn" Text="AddProduct" Clicked="AddBtn_Clicked"/> <CollectionView ItemsSource="{Binding Products}"> <CollectionView.ItemTemplate> <DataTemplate> <Grid Padding="10"> <Image Source="https://aka.ms/campus.jpg" Aspect="AspectFill" HeightRequest="100"/> <StackLayout Orientation="Horizontal"> <StackLayout BackgroundColor="Black" Opacity="0.7" Padding="10" VerticalOptions="End"> <Label Text="{Binding ProductName}" TextColor="White" FontSize="Title" /> <Label Text="{Binding Price, StringFormat='Price: {0:C}'}" TextColor="White" FontSize="Subtitle" /> </StackLayout> <Button Text="Edit" Command="{Binding EditProductCommand}" /> </StackLayout> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </ContentPage>
解决方案
问题根源:CollectionView的ItemTemplate内部的DataContext是集合中的单个Product对象,而非页面绑定的ProductViewModel,所以按钮找不到EditProductCommand。
解决步骤:
- 给ContentPage设置
x:Name,方便子控件引用页面的ViewModel - 修改按钮的Command绑定,指定绑定源为页面的ViewModel
修改后的XAML代码:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:ShoppingCart.Models" x:DataType="vm:ProductViewModel" x:Class="ShoppingCart.Pages.AdminPage" x:Name="AdminPageRoot" Title="AdminPage"> <VerticalStackLayout> <Button x:Name="AddBtn" Text="AddProduct" Clicked="AddBtn_Clicked"/> <CollectionView ItemsSource="{Binding Products}"> <CollectionView.ItemTemplate> <DataTemplate> <Grid Padding="10"> <Image Source="https://aka.ms/campus.jpg" Aspect="AspectFill" HeightRequest="100"/> <StackLayout Orientation="Horizontal"> <StackLayout BackgroundColor="Black" Opacity="0.7" Padding="10" VerticalOptions="End"> <Label Text="{Binding ProductName}" TextColor="White" FontSize="Title" /> <Label Text="{Binding Price, StringFormat='Price: {0:C}'}" TextColor="White" FontSize="Subtitle" /> </StackLayout> <Button Text="Edit" Command="{Binding BindingContext.EditProductCommand, Source={x:Reference AdminPageRoot}}" /> </StackLayout> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </ContentPage>
扩展优化(可选)
如果需要在EditProduct中获取当前点击的Product对象,可以修改ViewModel的命令为带参数版本:
[ICommand] public void EditProduct(Product product) { if(product != null) { App.Current.MainPage.DisplayAlert("编辑产品", $"产品ID:{product.ProductId}", "Ok"); } }
同时在XAML中添加CommandParameter传递当前Product:
<Button Text="Edit" Command="{Binding BindingContext.EditProductCommand, Source={x:Reference AdminPageRoot}}" CommandParameter="{Binding .}" />
内容的提问来源于stack exchange,提问作者Sparsh
相关产品推荐
相关产品推荐

