Xamarin MVVM 从另一个页面删除 Listview 项目

Posted

技术标签:

【中文标题】Xamarin MVVM 从另一个页面删除 Listview 项目【英文标题】:Xamarin MVVM Delete Listview Item from Another Page 【发布时间】:2020-02-07 03:46:12 【问题描述】:

您好,Xamarin 表单的新手。我有一个列表视图,我可以在选择项目时提取信息,类似于 Visual Studio 2017 xamarin 项目中提供的模板。

希望模板更完整,因为添加和更新效果很好,但我在创建删除方法时遇到了麻烦。数据已从 SQLite 中删除,但 ObservableCollection 不会刷新。

我尝试将类似的逻辑从添加和更新复制到删除。我尝试将另一个消息中心方法添加到我的构造函数中,但是在添加调试等调试时它没有被击中。不知道我错过了什么。还在我头上。

这是列表视图,它工作得很好

        <ContentPage.ToolbarItems>
        <ToolbarItem Text="-" Command="Binding ExecuteDeleteAllCommand"></ToolbarItem>
        <ToolbarItem Text="+" Clicked="InsertAuditClicked"></ToolbarItem>
    </ContentPage.ToolbarItems>
    <ContentPage.Padding>
        <OnIdiom>10, 10, 10, 10</OnIdiom>
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout>
            <ListView x:Name="AuditsListView"
                      ItemsSource="Binding AuditsCollection"
                      VerticalOptions="FillAndExpand"
                      HasUnevenRows="true"
                      RefreshCommand="Binding LoadAuditsCommand"
                      IsPullToRefreshEnabled="true"
                      IsRefreshing="Binding IsBusy, Mode=OneWay"
                      CachingStrategy="RecycleElement"
                      ItemSelected="OnAuditSelected">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid>
                                <StackLayout Grid.Column="0">
                                    <!-- <Label Text="Binding Id"
                                       LineBreakMode="NoWrap"
                                       Style="DynamicResource ListAuditTextStyle"
                                       FontSize="16"></Label>-->
                                    <Label Text="Binding AuditId"
                                       Style="DynamicResource ListAuditTextStyle"
                                       FontSize="16"></Label>
                                    <Label Text="Binding AuditCommand"
                                       LineBreakMode="NoWrap"
                                       Style="DynamicResource ListAuditDetailTextStyle"
                                       FontSize="13"></Label>
                                </StackLayout>
                                <StackLayout Grid.Column="1" VerticalOptions="CenterAndExpand" HorizontalOptions="EndAndExpand">
                                    <Label Text=">" FontSize="18"></Label>
                                </StackLayout>
                            </Grid>

                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>

这里是代码

    
        AuditsViewModel ViewModel;

        public AuditsPage()
        
            InitializeComponent();

            BindingContext = ViewModel = new AuditsViewModel();
        

        async void OnAuditSelected(object s, SelectedItemChangedEventArgs e)
        
            var m = e.SelectedItem as AuditModel;

            if (m == null)
                return;

            await Navigation.PushAsync(new AuditDetailPage(new AuditDetailViewModel(m))); // (new AuditDetailPage(new AuditDetailViewModel(m)));

            AuditsListView.SelectedItem = null;
        

        async void InsertAuditClicked(object sender, EventArgs e)
        

            await Navigation.PushModalAsync(new NavigationPage(new AuditNewPage()));

        

        protected override void OnAppearing()
        
            base.OnAppearing();

            if (ViewModel.AuditsCollection.Count == 0)
                ViewModel.LoadAuditsCommand.Execute(null);
        


    

这是视图模型

namespace AuditTest.ViewModels

    public class AuditsViewModel : BaseViewModel
    
        public ObservableCollection<AuditModel> AuditsCollection  get; set; 

        public Command LoadAuditsCommand  get; set; 

        public AuditsViewModel()
        
            Title = "Browse";
            AuditsCollection = new ObservableCollection<AuditModel>();
            LoadAuditsCommand = new Command(async () => await ExecuteLoadAuditsCommand());

            MessagingCenter.Subscribe<AuditNewPage, AuditModel>(this, "AddAudit", async (o, a) =>
            
                var n = a as AuditModel;
                AuditsCollection.Add(n);
                await App.MobileDataBase.InsertAuditAsync(n);
            );

            //MessagingCenter.Subscribe<AuditDetailPage, AuditModel>(this, "DeleteAudit", async (o, a) =>
            //
            //    var n = a as AuditModel;
            //    AuditsCollection.Remove(n);
            //    await App.MobileDataBase.DeleteAuditAsync(n);


            //);

        

        async Task ExecuteLoadAuditsCommand()
        
            if (IsBusy)
                return;

            IsBusy = true;

            try
            
                AuditsCollection.Clear();
                var a = await App.MobileDataBase.GetAuditsAsync(true); // var a = await DataSource.GetAuditsAsync(true);

                foreach (var i in a)
                
                    AuditsCollection.Add(i);
                
            
            catch (Exception ex)
            
                Debug.WriteLine(ex);
            
            finally
            
                IsBusy = false;
            
        

    

有一个带有点击事件的工具栏。这是后面的代码

    using AuditTest.Models;
using Xamarin.Forms;
using AuditTest.Views;
using System.Threading.Tasks;

namespace AuditTest.ViewModels

    public class AuditDetailViewModel : BaseViewModel
    
        public AuditModel AuditDetail  get; set; 

        public AuditDetailViewModel(AuditModel m = null)
        

            Title = m.AuditId.ToString(); // m?.AuditId;
            AuditDetail = m;

        

        public Command ExecuteEditAuditCommand
        
            get
            
                return new Command(async () =>
                
                    await DataSource.UpdateAuditAsync(AuditDetail);
                );
            
        

        public Command ExecuteDeleteAuditCommand
        
            get
            
                return new Command(async () =>
                
                    await App.MobileDataBase.DeleteAuditAsync(AuditDetail); // DataSource.DeleteAuditAsync(AuditDetail.AuditId));
                );
            
        

        public Task TestUpdateCommand()
        
            Task<bool> tt = App.MobileDataBase.UpdateAuditAsync(AuditDetail);

            return tt;
        

        public Task TestDeleteCommand()
        
            Task<bool> tt = App.MobileDataBase.DeleteAuditAsync(AuditDetail);
            MessagingCenter.Send(this, "DeleteAudit", this.AuditDetail); // await ViewModel.ExecuteDeleteAuditCommand(); // App.MobileDataBase.DeleteAuditAsync();
            return tt;

        
    

使用不同的属性和方法,但这里是内容页面的视图模型

    using AuditTest.Models;
using Xamarin.Forms;
using AuditTest.Views;
using System.Threading.Tasks;

namespace AuditTest.ViewModels

    public class AuditDetailViewModel : BaseViewModel
    
        public AuditModel AuditDetail  get; set; 

        public AuditDetailViewModel(AuditModel m = null)
        

            Title = m.AuditId.ToString(); // m?.AuditId;
            AuditDetail = m;

        

        public Command ExecuteEditAuditCommand
        
            get
            
                return new Command(async () =>
                
                    await DataSource.UpdateAuditAsync(AuditDetail);
                );
            
        

        public Command ExecuteDeleteAuditCommand
        
            get
            
                return new Command(async () =>
                
                    await App.MobileDataBase.DeleteAuditAsync(AuditDetail); // DataSource.DeleteAuditAsync(AuditDetail.AuditId));
                );
            
        

        public Task TestUpdateCommand()
        
            Task<bool> tt = App.MobileDataBase.UpdateAuditAsync(AuditDetail);

            return tt;
        

        public Task TestDeleteCommand()
        
            Task<bool> tt = App.MobileDataBase.DeleteAuditAsync(AuditDetail);
            MessagingCenter.Send(this, "DeleteAudit", this.AuditDetail); // await ViewModel.ExecuteDeleteAuditCommand(); // App.MobileDataBase.DeleteAuditAsync();
            return tt;

        
    

【问题讨论】:

DeleteAudit 消息是从 AuditDetailViewModel 发送的,所以对应的订阅也需要从 AuditDetailViewModel 监听表单消息,而不是 AuditDetailPage 【参考方案1】:

已修复。谢谢杰森,你太棒了!现在可以了。

取消注释并更改 ViewModel 构造函数上的消息中心订阅以指向另一个 ViewModel 发送

MessagingCenter.Subscribe<AuditDetailViewModel, AuditModel>(this, "DeleteAudit", async (o, a) =>
            
                var n = a as AuditModel;
                AuditsCollection.Remove(n);
                await App.MobileDataBase.DeleteAuditAsync(n);


            );

其他ViewModel上的Public Method还有这个

        public void MethodDeleteCommand()
        
            MessagingCenter.Send(this, "DeleteAudit", this.AuditDetail);
        

【讨论】:

以上是关于Xamarin MVVM 从另一个页面删除 Listview 项目的主要内容,如果未能解决你的问题,请参考以下文章

关于xamarin.forms在MVVM情况下如何DisplayActionSheet

如何将 Xamarin.Essentials MediaPicker 与 MVVM 和 DataBinding 一起使用

Xamarin MVVM 将数据传递到其他视图

Xamarin.Forms 条目 - 自定义行为和 MVVM

使用 mvvm 在 xamarin 表单中的视图之间传递数据

使用mvvm在xamarin表单中的视图之间传递数据