對于我的 Xamarin Forms 應用程式,我正在開發一個日歷頁面。我有一個 No-SQL 資料庫設定和作業,我有我的主日歷視圖頁面 (EventManagerPage) 和此頁面的后端 (EventManagerViewPage)。
我面臨的問題是如何讓系統知道 RefreshView 正在重繪 ?
正常的 Xamarin.Forms.IsBusy 指示器無法正常作業,我的頁面將繼續重繪 而不會停止。在我下拉頁面重繪 并單擊日期后,我可以告訴日歷事件存在,因為它們出現在日歷下方,但日歷本身不顯示存在的事件(日期每個事件的藍色方塊)。
我的 ViewModel 基于擴展 INotifyPropertyChanged 介面和 BaseViewModel 的自定義日歷 ViewModel。
使用 IsBusy 不會導致拋出任何錯誤,也不會導致除錯輸出中出現任何消??息。我已經嘗試了一些其他方法來嘗試讓重新加載在完成后停止,但這些都導致了阻止應用程式編譯的錯誤。
到目前為止,我已經嘗試創建一個自定義布林值來充當 IsBusy Xamarin.Forms 指示器,但這導致在資料背景關系中找不到成員的錯誤。
我還嘗試按照Microsoft Doc on RefreshViews中的示例進行操作。這也導致在資料背景關系中找不到成員的錯誤并且我無法設定refreshView.Command = refreshCommand;
(我不確定這是否對錯誤很重要)。
我把我的代碼放在下面。請注意,我使用的日歷是作者 MarvinE 的 Plugin.XCalendar。
我感謝任何人提供的任何幫助/建議!
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();
}
}
}
uj5u.com熱心網友回復:
您是否在 ViewModel 中為“IsBusy”創建了系結屬性,如下所示:
private bool _isBusy;
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
OnPropertyChanged("IsBusy");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/470499.html