RefreshView 不会停止刷新 - Xamarin Forms

RefreshView won't stop refreshing - Xamarin Forms

对于我的 Xamarin Forms 应用程序,我正在开发一个日历页面。我有一个 No-SQL 数据库设置和工作,我有我的主日历视图页面 (EventManagerPage) 和该页面的后端 (EventManagerViewPage)。

我面临的问题是如何让系统知道RefreshView正在刷新?

正常的Xamarin.Forms.IsBusy指示器没有工作,我的页面会不停地刷新。我可以告诉日历事件在那里,因为它们在我下拉页面刷新并单击日期后出现在日历下方,但日历本身不显示存在的事件(每个日期事件的蓝色方块)。

我的 ViewModel 基于扩展了 INotifyPropertyChanged 接口和 BaseViewModel 的自定义日历 ViewModel。

使用 IsBusy 不会导致抛出任何错误,也不会导致调试输出中出现任何消​​息。我已经尝试了其他一些方法来尝试让重新加载在完成后停止,但这些都导致了阻止应用程序编译的错误。

到目前为止,我已经尝试创建一个自定义布尔值来充当 IsBusy Xamarin.Forms 指示器,但这导致了在数据上下文中找不到成员的错误。

我还尝试按照 this Microsoft 文档中有关 RefreshViews 的示例进行操作。这也导致了在数据上下文中找不到成员的错误,我无法设置refreshView.Command = refreshCommand;(我不确定这是否对错误很重要)。

我已经把我的代码放在下面了。请注意,我使用的日历是作者 MarvinE 的 Plugin.XCalendar。
我感谢 help/suggestions 任何人提供的任何东西!

CalendarBaseViewModel.cs

using MvvmHelpers;
using PropertyChanged;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace PPA.ViewModels
{
    [AddINotifyPropertyChangedInterface]
    public abstract class CalendarBaseViewModel : BaseViewModel, INotifyPropertyChanged
    {
        #region Events
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        #region Methods
        protected virtual void OnPropertyChanged([CallerMemberName] string PropertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }
        #endregion
    }
}

EventManagerViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
using PPA.Models;
using System.Threading.Tasks;
using PPA.Views;
using PPA.Services;
using System.Diagnostics;

namespace PPA.ViewModels
{
    public class EventManagerViewModel : CalendarBaseViewModel
    {
        #region Properties
        public ObservableRangeCollection<Event> Events { get; }
        public ObservableRangeCollection<DateTime> SelectedDates { get; }
        public ObservableRangeCollection<Event> SelectedEvents { get; }

        #endregion

        public AsyncCommand AddEventCommand { get; }
        public AsyncCommand LoadEventsCommand { get; }

        IEventDataStore EventService;

        #region Constructors
        public EventManagerViewModel()
        {
            AddEventCommand = new AsyncCommand(OnAddEvent);
            LoadEventsCommand = new AsyncCommand(LoadEvents);
            EventService = DependencyService.Get<IEventDataStore>();

            Events = new ObservableRangeCollection<Event>();
            SelectedDates = new ObservableRangeCollection<DateTime>(); 
            SelectedEvents = new ObservableRangeCollection<Event>();


            SelectedDates.CollectionChanged += SelectedDates_CollectionChanged;

        }
        #endregion

        #region Methods
        private void SelectedDates_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            SelectedEvents.ReplaceRange(Events.Where(x => SelectedDates.Any(y => x.DateTime.Date == y.Date)).OrderByDescending(x => x.DateTime));
        }

        private async Task OnAddEvent()
        {
            await Shell.Current.GoToAsync(nameof(NewEventPage));
        }

        async Task LoadEvents()
        {
            IsBusy = true;
            // refreshview.IsRefreshing = true;
            try
            {
                Events.Clear();
                var events = await EventService.GetEventsAsync();
                foreach (var ev in events)
                {
                    Events.Add(ev);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
           IsBusy = false;
        } 
        


        public void OnAppearing()
        {
         IsBusy = true;
        }
        #endregion
    }
}

EventManagerPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="PPA.Views.EventManagerPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:Converters="clr-namespace:PPA.Converters"
    xmlns:Models="clr-namespace:PPA.Models"
    xmlns:ViewModels="clr-namespace:PPA.ViewModels"
    xmlns:xc="clr-namespace:XCalendar;assembly=XCalendar"
    xmlns:xcModels="clr-namespace:XCalendar.Models;assembly=XCalendar"
    xmlns:xct="http://xamarin.com/schemas/2020/toolkit" xmlns:xcConverters="clr-namespace:XCalendar.Converters;assembly=XCalendar" 
             x:DataType="ViewModels:EventManagerViewModel"
             x:Name="This"
    Title="Event Calendar"
    xct:SafeAreaEffect.SafeArea="True"
             >
    <ContentPage.Resources>
        <!--  Limits a string to a certain amount of characters  -->
        <xcConverters:StringCharLimitConverter x:Key="StringCharLimitConverter"/>
        <!--  Returns true if all bindings evaluate to true  -->
        <xct:VariableMultiValueConverter x:Key="AllTrueConverter" ConditionType="All"/>
        <!--  Inverts a binded boolean value  -->
        <xct:InvertedBoolConverter x:Key="InvertedBoolConverter"/>
    </ContentPage.Resources>
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add" Command="{Binding AddEventCommand}" />
    </ContentPage.ToolbarItems>

    <RefreshView x:DataType="ViewModels:EventManagerViewModel" Command="{Binding LoadEventsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
    <Grid
        ColumnSpacing="0"
        RowDefinitions="Auto,*"
        RowSpacing="0">

        <Frame
            Margin="10"
            Padding="0"
            BackgroundColor="White"
            CornerRadius="15">

            <xc:CalendarView
                x:Name="MainCalendarView"
                Grid.Row="0"
                DayNameTextColor="{StaticResource ContentTextColor}"
                NavigationArrowColor="{StaticResource ContentTextColor}"
                NavigationBackgroundColor="Transparent"
                NavigationTextColor="{StaticResource ContentTextColor}"
                SelectedDates="{Binding SelectedDates}"
                SelectionAction="Modify"
                SelectionType="Single">

                <xc:CalendarView.DayTemplate>
                    <DataTemplate x:DataType="{x:Type xcModels:CalendarDay}">
                        <!--  ContentView so that the margin is respected by the MonthView  -->
                        <ContentView>
                            <xc:CalendarDayView
                                Margin="2.5"
                                HeightRequest="43"
                                CalendarView="{Binding ., Source={x:Reference MainCalendarView}}"
                                CurrentMonthTextColor="{StaticResource CalendarBackgroundTextColor}"
                                DateTime="{Binding DateTime}"
                                OutOfRangeTextColor="{StaticResource CalendarTertiaryColor}"
                                SelectedTextColor="{StaticResource CalendarPrimaryTextColor}"
                                TodayBorderColor="{StaticResource CalendarPrimaryColor}"
                                TodayTextColor="{StaticResource CalendarBackgroundTextColor}">

                                <xc:CalendarDayView.ControlTemplate>
                                    <ControlTemplate>
                                        <!--  Using a Grid to stack views on the z axis  -->
                                        <Grid RowSpacing="2">

                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="1.5*"/>
                                                <RowDefinition/>
                                            </Grid.RowDefinitions>

                                            <!--  ContentPresenter displays the default content for the control  -->
                                            <ContentPresenter
                                                Grid.Row="0"
                                                Grid.RowSpan="2"
                                                VerticalOptions="Center"/>

                                            <StackLayout
                                                Grid.Row="1"
                                                HorizontalOptions="Center"
                                                Orientation="Horizontal"
                                                Spacing="2.5">

                                                <!--  I want the event indicators to only be visible when the DateTime is in the currently navigated month  -->
                                                <StackLayout.IsVisible>
                                                    <MultiBinding Converter="{StaticResource AllTrueConverter}">
                                                        <!--  TemplatedParent refers to the view that the ControlTemplate resides in  -->
                                                        <Binding Path="IsCurrentMonth" Source="{RelativeSource TemplatedParent}"/>
                                                        <Binding
                                                            Converter="{StaticResource InvertedBoolConverter}"
                                                            Path="IsOutOfRange"
                                                            Source="{RelativeSource TemplatedParent}"/>
                                                    </MultiBinding>
                                                </StackLayout.IsVisible>

                                                <BindableLayout.ItemsSource>
                                                    <Binding Path="DateTime.Date" Source="{RelativeSource TemplatedParent}">
                                                        <Binding.Converter>
                                                            <Converters:EventWhereConverter
                                                                Items="{Binding BindingContext.Events, Source={x:Reference This}}"
                                                                UseTimeComponent="False"
                                                                WhiteList="True"/>
                                                        </Binding.Converter>
                                                    </Binding>
                                                </BindableLayout.ItemsSource>

                                                <BindableLayout.ItemTemplate>
                                                    <DataTemplate x:DataType="{x:Type Models:Event}">
                                                        <BoxView
                                                            CornerRadius="100"
                                                            HeightRequest="7"
                                                            HorizontalOptions="CenterAndExpand"
                                                            VerticalOptions="Center"
                                                            WidthRequest="7"
                                                            Color="Blue"/>
                                                    </DataTemplate>
                                                </BindableLayout.ItemTemplate>

                                            </StackLayout>

                                        </Grid>
                                    </ControlTemplate>
                                </xc:CalendarDayView.ControlTemplate>

                            </xc:CalendarDayView>
                        </ContentView>
                    </DataTemplate>
                </xc:CalendarView.DayTemplate>

            </xc:CalendarView>

        </Frame>

        <CollectionView Grid.Row="1" ItemsSource="{Binding SelectedEvents}">

            <CollectionView.EmptyView>
                <Label
                    FontAttributes="Bold"
                    FontSize="20"
                    HorizontalTextAlignment="Center"
                    Text="No Events on Selected Date(s)"
                    TextColor="{StaticResource ContentTextColor}"
                    VerticalTextAlignment="Center"/>
            </CollectionView.EmptyView>
            <CollectionView.ItemsLayout>
                <LinearItemsLayout ItemSpacing="0" Orientation="Vertical"/>
            </CollectionView.ItemsLayout>

            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="{x:Type Models:Event}">
                    <ContentView Padding="5">
                        <Frame
                            Padding="0"
                            BackgroundColor="{StaticResource ContentBackgroundColor}"
                            CornerRadius="10">
                            <StackLayout Orientation="Horizontal" Spacing="0">
                                <BoxView BackgroundColor="CornflowerBlue" WidthRequest="20"/>

                                <StackLayout Padding="10" Spacing="0">
                                    <Label
                                        FontAttributes="Bold"
                                        FontSize="20"
                                        Text="{Binding DateTime, StringFormat='{0: dd MMMM HH:mm}'}"
                                        TextColor="{StaticResource ContentTextColor}"
                                        VerticalTextAlignment="Center"/>
                                    <Label
                                        FontSize="16"
                                        Text="{Binding Title}"
                                        TextColor="{StaticResource ContentTextColor}"
                                        Margin="5,0,0,0"/>
                                    <Label
                                        Margin="5,10,0,0"
                                        FontSize="14"
                                        Text="{Binding Description}"
                                        TextColor="{StaticResource ContentTextColor}"/>
                                </StackLayout>
                            </StackLayout>
                        </Frame>
                    </ContentView>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

    </Grid>
     </RefreshView>
</ContentPage>

EventManagerPage.xaml.cs

using PPA.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace PPA.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]

    public partial class EventManagerPage : ContentPage
    {
        EventManagerViewModel _viewModel;
        public EventManagerPage()
        {

            InitializeComponent();
            BindingContext = _viewModel = new EventManagerViewModel();
            
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            _viewModel.OnAppearing();
        }
    }
}

您是否在 ViewModel 中为“IsBusy”创建了绑定 属性,如下所示:

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