.NET MAUI中SwipeView滑动触发CollectionView选中项的问题
问题解决:CollectionView嵌套SwipeView时滑动误触发选中跳转的问题
核心原因
Android平台上,CollectionView的SelectedItem/SelectionChangedCommand会将滑动动作误识别为选中操作,导致用户还没选择SwipeView的操作项就触发页面跳转。
解决方案步骤
1. 替换CollectionView选中逻辑为ItemTapCommand
ItemTapCommand仅响应明确的轻触动作,不会被滑动事件误触发,彻底替代原有的选中绑定逻辑。
2. 拦截SwipeView滑动事件
通过ViewModel的状态标记,确保滑动SwipeView时不执行跳转逻辑。
3. 优化触摸事件优先级
确保SwipeView优先捕获触摸事件,避免事件冒泡到CollectionView。
完整修改代码
XAML代码修改
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" x:Class="GastoMisto.Pages.MateriaisGestaoLista" Title="Materiais"> <ContentPage.ToolbarItems> <ToolbarItem Command="{Binding AdicionarMaterialCommand}" IconImageSource="Resources/Images/plus.svg" /> </ContentPage.ToolbarItems> <ContentPage.Behaviors> <toolkit:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadDataCommand}" /> </ContentPage.Behaviors> <VerticalStackLayout Padding="5"> <!-- 移除SelectedItem、SelectionChangedCommand、SelectionMode,改用ItemTapCommand --> <CollectionView ItemsSource="{Binding Materiais}" ItemTapCommand="{Binding MaterialTappedCommand}" x:Name="cMateriaisView"> <CollectionView.ItemTemplate> <DataTemplate> <!-- 添加滑动开始/结束事件绑定 --> <SwipeView SwipeStarted="{Binding Source={x:Reference cMateriaisView}, Path=BindingContext.OnSwipeStarted}" SwipeEnded="{Binding Source={x:Reference cMateriaisView}, Path=BindingContext.OnSwipeEnded}"> <SwipeView.LeftItems> <SwipeItems Mode="Reveal"> <SwipeItem Text="Desativar" Command="{Binding DesativarCommand, Source={x:Reference cMateriaisView}}" CommandParameter="{Binding .}" /> <SwipeItem Text="Apagar" Command="{Binding ApagarCommand, Source={x:Reference cMateriaisView}}" CommandParameter="{Binding .}" /> <SwipeItem Text="Consultar" Command="{Binding ConsultarCommand, Source={x:Reference cMateriaisView}}" CommandParameter="{Binding .}" /> </SwipeItems> </SwipeView.LeftItems> <!-- 设置InputTransparent确保触摸事件优先被SwipeView捕获 --> <Grid RowDefinitions="Auto,Auto" ColumnDefinitions="Auto,Auto" ColumnSpacing="5" InputTransparent="False"> <Label Text="{Binding Codigo}" FontAttributes="Bold" Grid.Row="0" Grid.Column="0" /> <Label Text="{Binding Designacao}" Grid.Row="0" Grid.Column="1" /> <Label Text="{Binding Notas}" Grid.Row="1" Grid.ColumnSpan="2" /> </Grid> </SwipeView> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </ContentPage>
ViewModel代码修改
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace GastoMisto.ViewModels { public class MateriaisGestaoListaViewModel : INotifyPropertyChanged { #region INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion private ObservableCollection<Model.Material> _materiais; public ObservableCollection<Model.Material> Materiais { get => _materiais; set { _materiais = value; OnPropertyChanged(); // 修复原代码缺失的属性变更通知 } } // 标记当前是否处于滑动状态 private bool _isSwiping; // 给操作命令添加参数,直接获取当前Material对象 public ICommand DesativarCommand => new Command<Model.Material>(async (material) => await Task.FromException<NotImplementedException>(new NotImplementedException())); public ICommand ApagarCommand => new Command<Model.Material>(async (material) => await Task.FromException<NotImplementedException>(new NotImplementedException())); public ICommand ConsultarCommand => new Command<Model.Material>(async (material) => await Task.FromException<NotImplementedException>(new NotImplementedException())); public ICommand LoadDataCommand => new Command(async () => await fillData()); // 替换原MaterialSelectedCommand为ItemTapCommand,接收点击的Material对象 public ICommand MaterialTappedCommand => new Command<Model.Material>(async (material) => await SelecionaMaterial(material)); // 滑动开始时标记状态 public ICommand OnSwipeStarted => new Command(() => _isSwiping = true); // 滑动结束时重置状态 public ICommand OnSwipeEnded => new Command(() => _isSwiping = false); public ICommand AdicionarMaterialCommand => new Command(async () => await Shell.Current.GoToAsync("Materiais/Ficha")); public MateriaisGestaoListaViewModel() { _materiais = new ObservableCollection<Model.Material>(); MessagingCenter.Subscribe<MateriaisGestaoFichaViewModel>(this, Messages.Refresh, async (sender) => await fillData()); } private async Task fillData() { Materiais.Clear(); var materiaisEmBd = await App.DbSingleton.Materiais.GetAll(); foreach (var esteMaterial in materiaisEmBd) { Materiais.Add(esteMaterial); } } private async Task SelecionaMaterial(Model.Material material) { // 若处于滑动状态,直接返回不执行跳转 if (material == null || _isSwiping) return; var navigationParameter = new Dictionary<string, object>() { { "MatEmQuestao", material } }; await Shell.Current.GoToAsync("Materiais/Ficha", navigationParameter); } } }
内容的提问来源于stack exchange,提问作者Morv
相关产品推荐
相关产品推荐

