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

Xamarin.Forms中RemoveCommand绑定无效问题求助

问题:Xamarin.Forms中RemoveCommand点击无响应,绑定方式存疑

我实现了删除数据库中Note的RemoveCommand,命令能正常显示,但点击后没有任何反应。怀疑是绑定方式的问题,试过多种把RefreshCommand绑定到MenuItem的方法,要么刷新时崩溃,要么删不掉笔记。以下是我的代码:


MyNotePage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     xmlns:model="clr-namespace:MyApp.Models"
     xmlns:mvvm="clr-namespace:MvvmHelpers;assembly=MvvmHelpers"
     xmlns:viewmodels="clr-namespace:MyApp.ViewModels"
     xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
     x:Class="MyApp.MyNotePage"
     x:DataType="viewmodels:MyNoteViewModel"
     BackgroundColor="White">
<ContentPage.BindingContext>
    <viewmodels:MyNoteViewModel/>
</ContentPage.BindingContext>

<ContentPage.Resources>
    <ResourceDictionary>
        <xct:ItemSelectedEventArgsConverter x:Key="ItemSelectedEventArgsConverter"/>
    </ResourceDictionary>
</ContentPage.Resources>

<ContentPage.ToolbarItems>
    <ToolbarItem Text="Add" Command="{Binding AddCommand}"/>
</ContentPage.ToolbarItems>

<ListView
BackgroundColor="Transparent"
CachingStrategy="RecycleElement"
HasUnevenRows="True"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
ItemsSource="{Binding Note}"
RefreshCommand="{Binding RefreshCommand}"
RefreshControlColor="DarkViolet"
SelectionMode="None"
SeparatorVisibility="None">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="model:Note">
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem x:DataType="viewmodels:MyNoteViewModel"
                    Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:MyNoteViewModel}}, Path=RemoveCommand}" 
                    CommandParameter="{Binding}"
                    IsDestructive="True"
                    Text="Delete"/>
                </ViewCell.ContextActions>
                <Grid Padding="10">
                    <Frame CornerRadius="20" HasShadow="True">
                        <StackLayout Orientation="Horizontal">
                            <StackLayout VerticalOptions="Center">
                                <Label
                                FontSize="Large"
                                Text="{Binding Name}"
                                VerticalOptions="Center"/>
                                <Label
                                FontSize="Small"
                                Text="{Binding Id}"
                                VerticalOptions="Center"/>
                            </StackLayout>
                        </StackLayout>
                    </Frame>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

NoteService.cs

namespace MyApp.Services
{
    public static class NoteService
    {

        static SQLiteAsyncConnection db;
        static async Task Init()
        {

            if (db != null)
                return;
            {
                var databasePath = Path.Combine(FileSystem.AppDataDirectory, "MyData.db");

                db = new SQLiteAsyncConnection(databasePath);

                await db.CreateTableAsync<Note>();
            }
        }

        public static async Task AddNote(string name)
        {
            await Init();
            var note = new Note()
            {
                Name = name,
            };

            await db.InsertAsync(note);

        }
        public static async Task RemoveNote(int id)
        {
            await Init();
            await db.DeleteAsync<Note>(id);

        }
        public static async Task<IEnumerable<Note>> GetNote()
        {
            await Init();

            var note = await db.Table<Note>().ToListAsync();
            return note;

        }

    }
}

MyNoteViewModel.cs

namespace MyApp.ViewModels
{
    public class MyNoteViewModel : ViewModelBase
    {

        public ObservableRangeCollection<Note> Note { get; }
        public AsyncCommand RefreshCommand { get; }

        public AsyncCommand AddCommand { get; }

        public AsyncCommand<Note> RemoveCommand { get; }


        public MyNoteViewModel()
        {

            Note = new ObservableRangeCollection<Note>();

            RefreshCommand = new AsyncCommand(Refresh);
            AddCommand = new AsyncCommand(Add);
            RemoveCommand = new AsyncCommand<Note>(Remove);
        }

        async Task Add()
        {
            var name = await App.Current.MainPage.DisplayPromptAsync("Notes", "Enter your notes here");
            await NoteService.AddNote(name);
            await Refresh();
        }

        async Task Remove(Note note)
        {
            await NoteService.RemoveNote(note.Id);
            await Refresh();
        }


        async Task Refresh()
        {
            IsBusy = true;
            await Task.Delay(2000);
            Note.Clear();
            var notes = await NoteService.GetNote();
            Note.AddRange(notes);
            IsBusy = false;
        }
    }
}

解决方案

你的MenuItem绑定问题出在x:DataType的设置上——在DataTemplate内部,你给MenuItem指定了x:DataType="viewmodels:MyNoteViewModel",这会干扰绑定上下文的解析逻辑,导致RelativeSource无法正确找到页面的ViewModel实例。

修改步骤

  1. 直接移除MenuItem上的x:DataType="viewmodels:MyNoteViewModel"属性
  2. 保留原有的Command绑定和CommandParameter绑定,确保能正确获取ViewModel的RemoveCommand和当前Note实例

修改后的MenuItem代码:

<MenuItem 
    Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodels:MyNoteViewModel}}, Path=RemoveCommand}" 
    CommandParameter="{Binding}"
    IsDestructive="True"
    Text="Delete"/>

额外检查点

  • 确认Note模型的Id字段标记了[PrimaryKey, AutoIncrement]特性,否则SQLite的DeleteAsync(id)无法准确定位到要删除的记录
  • 确保继承的ViewModelBase正确实现了INotifyPropertyChanged接口,IsBusy属性变更时能触发属性通知,避免下拉刷新状态异常

内容的提问来源于stack exchange,提问作者PuineaGip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 08:54:16