【问题标题】:Refresh Xamarin ListView on Add or Delete在添加或删除时刷新 Xamarin ListView
【发布时间】:2017-09-11 19:05:18
【问题描述】:

删除记录或从其他视图添加记录后,我无法刷新 Xamarin ListView。

我有一个视图 (RaceList.xaml),它列出了从 ViewModel 获得的可观察集合中的种族。

RaceList.xaml.cs

using System.Collections.Generic;
using TechsportiseApp.API;
using TechsportiseApp.API.Models;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using TechsportiseApp.MainUI.ViewModels;
using System;

namespace TechsportiseApp.MainUI
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class RaceList : ContentPage
    {
        public List<Race> Races { get; set; }

        public RaceList()
        {
            InitializeComponent();

            var viewModel = new RaceListViewModel();
            BindingContext = viewModel;



            ToolbarItems.Add(new ToolbarItem("New", "Add.png", async () =>
            {
                await Navigation.PushAsync(new RaceNew());
            }));
        }

        public void OnDelete(object sender, EventArgs e)
        {
            var menuitem = ((MenuItem)sender);
            var stringraceid = menuitem.CommandParameter.ToString();
            int raceid = Int32.Parse(stringraceid);

            RacesAPI.DeleteRace(raceid);
            MessagingCenter.Send(this, "RaceListChanged");
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            RacesAPI.GetRaces();
            //LoadServerRegisteredCitizen is a method which i used to load items inside the listview        
        }

        async void Handle_ItemTapped(object sender, Xamarin.Forms.ItemTappedEventArgs e)
        {
            if (e.Item == null)
                return;
            var race = e.Item as Race;

            await Navigation.PushAsync(new RaceView(race));
            //Deselect Item
            ((ListView)sender).SelectedItem = null;
        }


    }
}

RaceList.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TechsportiseApp.MainUI.RaceList"
             Title="Races">
    <!--SelectedItem="{Binding RaceSelected, Mode=TwoWay} "-->
    <ListView ItemsSource="{Binding Races}"
        ItemTapped="Handle_ItemTapped"
        SeparatorVisibility = "None"
        IsPullToRefreshEnabled="true" 
        RefreshCommand="{Binding RefreshCommand}" 
        IsRefreshing="{Binding IsBusy}">

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.ContextActions>
                       <MenuItem Clicked="OnDelete" CommandParameter="{Binding Id}" Text="Delete" IsDestructive="True" />
                    </ViewCell.ContextActions>
                    <StackLayout>
                        <Label Text="{Binding Name}"  />
                        <Label Text="{Binding RaceDate}" />
                        <BoxView Color="#B2B2B2" HeightRequest="1" />
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

RaceListViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RestSharp;
using TechsportiseApp.API.Models;
using Xamarin.Forms;
using TechsportiseApp.API;
using System.Windows.Input;
using System.Collections.ObjectModel;

namespace TechsportiseApp.MainUI.ViewModels
{
    public class RaceListViewModel : INotifyPropertyChanged
    {
        public RaceListViewModel()
        {
            _refreshCommand = new Command(RefreshList);

            MessagingCenter.Subscribe<RaceListViewModel>(this, "RaceListChanged", sender => {
                Races = RacesAPI.GetRaces();
                OnPropertyChanged("Id");
            });
        }

        public void RefreshList()
        {
            //Refreshes list on Pull to Refresh
           Races = RacesAPI.GetRaces();
        }

        int _id;
        public int Id
        {
            get
            {
                return _id;
            }
            set
            {
                if (_id != value)
                {
                    _id = value;
                    // trigger some action to take such as updating other labels or fields
                    OnPropertyChanged("Id");
                }
            }
        }

        int _name;
        public int Name
        {
            get
            {
                return _name;
            }
            set
            {
                if (_name != value)
                {
                    _name = value;

                    // trigger some action to take such as updating other labels or fields
                    OnPropertyChanged("Name");
                }
            }
        }

        private ObservableCollection<Race> _races;
        public ObservableCollection<Race> Races
        {
            get
            {
                var racelist = RacesAPI.GetRaces();
                IsBusy = false;
                return racelist;
            }
            set
            {
                if (_races != value)
                {
                    _races = value;
                    // trigger some action to take such as updating other labels or fields
                    OnPropertyChanged("Races");
                }
            }
        }

        private Race _raceSelected;
        public Race RaceSelected
        {
            get
            {
                return RaceSelected;
            }
            set
            {
                if (RaceSelected != value)
                {
                    RaceSelected = value;
                    OnPropertyChanged("RaceSelected");
                }
            }
        }



        private bool _isBusy;
        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                if (_isBusy == value)
                    return;

                _isBusy = value;
                OnPropertyChanged("IsBusy");
            }
        }



        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            var changed = PropertyChanged;
            if (changed != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        Command _refreshCommand;
        public Command RefreshCommand
        {
            get
            {
                return _refreshCommand;
            }
        }
    }
}

按下工具栏中的“创建”按钮后,我会进入一个新视图,该视图显示一个空白表单,允许我为新比赛填写数据。保存后,它将 JSON 推送到我的 API,如果成功,则将它们重定向到编辑页面。

RaceNew.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             x:Class="TechsportiseApp.MainUI.RaceNew"
             Title="New Race">
    <ContentPage.Content>
    <ScrollView  Orientation = "Vertical" VerticalOptions="StartAndExpand">
    <StackLayout Padding="0,20,0,0">
        <Label x:Name="labelName" Text="Name" />
            <Entry x:Name="entryName"  />
        <Label x:Name="labelDescription" Text="Description" />
            <Editor x:Name="editorDescription"  />
       <Label x:Name="labelContactName" Text="Contact Name" />
            <Entry x:Name="entryContactName"  />
        <Label x:Name="labelContactNumber" Text="Contact Number" />
            <Entry x:Name="entryContactNumber" Keyboard="Telephone"  />
        <Label x:Name="labelContactEmail" Text="ContactEmail" />
            <Entry x:Name="entryContactEmail" Keyboard="Email"   />
        <Label x:Name="labelRaceDate" Text="Race Date" />
                <DatePicker x:Name="datepickerRaceDate" Date="{Binding Source={x:Static sys:DateTime.Now}" Format="ddd d MMMM yyyy" />
        <Label x:Name="labelRaceStartTime" Text="Race Time" />
                <TimePicker x:Name="timepickerRaceStartTime"  />
        <Label x:Name="labelMaxEntries" Text="Max Entries" />
                <Entry x:Name="entryMaxEntries"  Keyboard="Numeric"  />
        <Label x:Name="labelCurrentEntries" Text="Current Entries" />
                <Entry x:Name="entryCurrentEntries"  Keyboard="Numeric" />
        <Label x:Name="labelIsOpenForEntries" Text="Open For Entries" />
            <Switch x:Name="switchIsOpenForEntries"  />
        <Label x:Name="labelIsPublished" Text="Published" />
            <Switch x:Name="switchIsPublished"  />        
    </StackLayout>
    </ScrollView>
    </ContentPage.Content>
</ContentPage>

RaceNew.xaml.cs

using System;
using TechsportiseApp.API;
using TechsportiseApp.API.Models;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace TechsportiseApp.MainUI
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class RaceNew : ContentPage
    {
        public RaceNew()
        {
            InitializeComponent();

            ToolbarItems.Add(new ToolbarItem("Create", "", async () =>

            {
                var saverace = new Race();
                saverace.ContactEmail = entryContactEmail.Text;
                saverace.ContactName = entryContactName.Text;
                saverace.ContactNumber = entryContactNumber.Text;
                saverace.CurrentEntries = 0;
                saverace.Description = editorDescription.Text;
                saverace.IsOpenForEntries = switchIsOpenForEntries.IsToggled;
                saverace.IsPublished = switchIsPublished.IsToggled;
                saverace.IsComplete = false;
                saverace.MaxEntries = System.Convert.ToInt32(entryMaxEntries.Text);
                saverace.Name = entryName.Text;
                saverace.RaceDate = datepickerRaceDate.Date;

                var timestring = string.Format("{0:00}:{1:00}:{2:00}", timepickerRaceStartTime.Time.Hours, timepickerRaceStartTime.Time.Minutes, timepickerRaceStartTime.Time.Seconds);
                saverace.RaceStartTime = timestring;

                var response = RacesAPI.CreateRace(saverace);
                if (response.Code == "Created")
                {
                    saverace.Id = response.ReturnedId;
                    Navigation.InsertPageBefore(new RaceView(saverace), this);
                    await Navigation.PopAsync();

                }
                //Error response
                else
                {
                    await DisplayAlert("Error: " + response.Code, "There has been an error creating your race. " + response.Content, "OK");
                }
            }));
        }


        async void OnBackButtonClicked(object sender, EventArgs e)
        {
            await Navigation.PopAsync();
        }
    }
}

在此页面中,我只需按“返回”按钮,它就会返回到我的 RaceList 视图。

问题是,列表视图没有刷新 - 它没有注册新种族的添加。

此外,在我的 RaceList.xaml.cs 中,您可以看到我还使用了一个删除按钮。当我从列表中删除项目时,它也不会刷新!

有什么想法吗?

【问题讨论】:

  • 您正在绑定到 OC 的实例,但每次刷新或更新时,您都会返回一个新的 OC 实例,而不是更新您绑定的实例。这确实违背了使用 OC 的目的。
  • 我最初使用的是 List,现在有很多可能是冗余的代码,因为我正在尝试各种不同的方法来刷新 ListView。我真正想做的是在页面之间共享绑定的视图模型,因为我认为这样可以解决问题,但我不知道该怎么做。

标签: c# xaml listview xamarin xamarin.forms


【解决方案1】:

重写 Xamarin.Forms.Page.OnAppearing 方法并调用 ViewModel 的 RefreshList() 方法。

RacelistViewModel Viewmodel = (RaceListViewModel)This.DataContext; ViewModel.RefreshList();

【讨论】:

  • 这几乎做到了......稍微错字更正但破解了它。谢谢! RaceListViewModel Viewmodel = (RaceListViewModel)this.BindingContext; Viewmodel.RefreshList();
【解决方案2】:

我不知道,但是

public List<Race> Races { get; set; }

List,而不是ObservableCollection

【讨论】:

  • 他的虚拟机中有一个 OC
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
相关资源
最近更新 更多