You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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。

解决步骤:

  1. 给ContentPage设置x:Name,方便子控件引用页面的ViewModel
  2. 修改按钮的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:19:53