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

.NET MAUI笔记应用中ListView单元格编辑功能实现求助

.NET MAUI ListView 单元格编辑实现方案

首先先修正你现有代码中的语法错误,这些错误会导致程序无法正常运行:

修正后的基础版 ViewModel

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;

internal partial class NotesViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<Note> notes = new();

    [ObservableProperty]
    private Note note = new(); // 修正笔误:移除多余的 notes 字段名

    [RelayCommand]
    private void Save()
    {
        Notes.Add(Note);
        Note = new Note();
    }
}

修正后的带参数 Save 方法 ViewModel

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;

internal partial class NotesViewModel : ObservableObject
{
    [ObservableProperty]
    private ObservableCollection<Note> notes = new();

    [ObservableProperty]
    private Note note = new(); // 修正笔误

    [RelayCommand]
    private void Save(Note? targetNote)
    {
        if (targetNote is null)
        {
            // 添加新笔记
            Notes.Add(Note);
            Note = new Note();
        }
        else
        {
            // 更新现有笔记:直接修改属性即可,无需重新实例化
            targetNote.OnPropertyChanged(nameof(Note.Title));
            targetNote.OnPropertyChanged(nameof(Note.Detail));
        }
    }
}

关键前提:Note 模型必须实现属性变更通知

你的 Note 类需要继承 ObservableObject(来自 CommunityToolkit.Mvvm),否则修改属性后 ListView 不会自动更新 UI:

using CommunityToolkit.Mvvm.ComponentModel;

public partial class Note : ObservableObject
{
    [ObservableProperty]
    private string title = string.Empty;

    [ObservableProperty]
    private string detail = string.Empty;

    // 可选:用于ListView内直接编辑的状态控制
    [ObservableProperty]
    private bool isEditing;
}

方案一:点击单元格跳转到编辑页面(适合新手,逻辑简单)

这种方式流程清晰,容易理解,适合刚接触 MVVM 的开发者:

1. 修改 ListView 绑定,传递选中的笔记

替换原有的 ItemTapped 事件,用绑定命令传递选中项:

<ListView ItemsSource="{Binding Notes}" 
          SelectedItem="{Binding SelectedNote}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="{x:Type model:Note}">
            <TextCell Text="{Binding Title}" 
                      Detail="{Binding Detail}" 
                      TextColor="#9a26ff"/>
        </DataTemplate>
    </ListView.ItemTemplate>
    <ListView.Behaviors>
        <toolkit:EventToCommandBehavior 
            EventName="ItemTapped"
            Command="{Binding EditNoteCommand}"
            CommandParameter="{Binding SelectedItem, Source={RelativeSource Self}}"/>
    </ListView.Behaviors>
</ListView>

(需要先安装 CommunityToolkit.Maui NuGet 包以使用 EventToCommandBehavior)

2. 在 ViewModel 中添加编辑相关属性和命令

internal partial class NotesViewModel : ObservableObject
{
    // ... 原有代码 ...

    [ObservableProperty]
    private Note? selectedNote;

    [RelayCommand]
    private async Task EditNote(Note? note)
    {
        if (note is null) return;
        // 跳转到编辑页面,传入选中的笔记对象
        await App.Current.MainPage.Navigation.PushAsync(new NoteEditPage(note));
    }
}

3. 创建编辑页面(NoteEditPage)

编辑页面直接绑定到传入的 Note 对象:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourApp.NoteEditPage"
             Title="编辑笔记">
    <VerticalStackLayout Padding="16">
        <Entry Placeholder="标题" Text="{Binding Title}" />
        <Editor Placeholder="内容" Text="{Binding Detail}" HeightRequest="200" />
        <Button Text="保存" Command="{Binding SaveCommand}" CommandParameter="{Binding .}" />
    </VerticalStackLayout>
</ContentPage>

编辑页面的 ViewModel:

public partial class NoteEditPageViewModel : ObservableObject
{
    public Note CurrentNote { get; }

    public NoteEditPageViewModel(Note note)
    {
        CurrentNote = note;
    }

    [RelayCommand]
    private async Task Save(Note note)
    {
        // 直接返回即可,Note是引用类型,修改已同步到原集合
        await App.Current.MainPage.Navigation.PopAsync();
    }
}

方案二:ListView 内直接编辑(更直观)

这种方式无需跳转页面,直接在单元格内完成编辑:

1. 自定义 ViewCell,切换显示/编辑状态

替换原有的 TextCell,用 ViewCell 包含显示和编辑控件:

<ListView ItemsSource="{Binding Notes}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="{x:Type model:Note}">
            <ViewCell>
                <VerticalStackLayout>
                    <!-- 显示状态 -->
                    <Frame IsVisible="{Binding IsEditing, Converter={StaticResource InverseBooleanConverter}}">
                        <GestureRecognizers>
                            <TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:NotesViewModel}}, Path=ToggleEditCommand}" CommandParameter="{Binding .}"/>
                        </GestureRecognizers>
                        <VerticalStackLayout>
                            <Label Text="{Binding Title}" FontSize="Headline" />
                            <Label Text="{Binding Detail}" FontSize="Body" Opacity="0.7" />
                        </VerticalStackLayout>
                    </Frame>

                    <!-- 编辑状态 -->
                    <VerticalStackLayout IsVisible="{Binding IsEditing}">
                        <Entry Text="{Binding Title}" />
                        <Editor Text="{Binding Detail}" HeightRequest="100" />
                        <HorizontalStackLayout>
                            <Button Text="保存" Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:NotesViewModel}}, Path=SaveCommand}" CommandParameter="{Binding .}" />
                            <Button Text="取消" Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:NotesViewModel}}, Path=CancelEditCommand}" CommandParameter="{Binding .}" />
                        </HorizontalStackLayout>
                    </VerticalStackLayout>
                </VerticalStackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

2. 添加布尔值反转转换器

在页面资源或全局资源中添加:

<ResourceDictionary>
    <converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</ResourceDictionary>

转换器代码:

public class InverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }
}

3. 在 ViewModel 中添加编辑控制命令

internal partial class NotesViewModel : ObservableObject
{
    // ... 原有代码 ...

    [RelayCommand]
    private void ToggleEdit(Note note)
    {
        note.IsEditing = !note.IsEditing;
    }

    [RelayCommand]
    private void CancelEdit(Note note)
    {
        note.IsEditing = false;
        // 可选:如果需要恢复编辑前内容,可以提前保存副本并在这里还原
    }

    [RelayCommand]
    private void Save(Note note)
    {
        note.IsEditing = false;
        // 这里可以添加持久化逻辑,比如保存到本地数据库
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 04:00:07