如何在自定义日历控件中滚动到今天?

问题描述 投票:0回答:0

我正在我的

CalendarView
中实现水平
Maui application

当应用程序启动时,我的计划日历会自动滚动到今天。然而,这并没有按预期工作,但是当我导航到另一个选项卡并返回时,它就可以工作了。

我在

ScrollTo
方法中调用
OnAppearing
方法

我的自定义日历视图

<?xml version="1.0" encoding="utf-8" ?>
    <StackLayout
        x:Class="App.Controls.CalendarView"
        xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:local="clr-namespace:App"
        xmlns:controls="clr-namespace:App.Controls"
        xmlns:models="clr-namespace:App.Models"
        x:Name="this">
    
        <StackLayout Orientation="Horizontal">
            <Label
                FontSize="Subtitle"
                HorizontalOptions="Start"
                Text="{Binding Source={x:Reference this}, Path=Today, StringFormat='{0:MMMM}'}"
                TextColor="{DynamicResource TextColor}"
                VerticalOptions="Center" />
            <Button
                Padding="10"
                BorderWidth="0"
                Clicked="JumpToToday_Button_Clicked"
                CornerRadius="10"
                FontAttributes="Bold"
                HeightRequest="40"
                HorizontalOptions="EndAndExpand"
                Style="{DynamicResource PrimaryActionOutlineButtonStyle}"
                Text="Jump to today"
                TextTransform="Uppercase"
                VerticalOptions="Center" />
        </StackLayout>
        <CollectionView
            x:Name="DateCollectionView"
            ItemsSource="{Binding Source={x:Reference this}, Path=Dates}"
            ItemsUpdatingScrollMode="KeepLastItemInView">
            <CollectionView.ItemsLayout>
                <LinearItemsLayout ItemSpacing="10" Orientation="Horizontal" />
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="models:CalendarModel">
                    <controls:CardView
                        Padding="10"
                        RowDefinitions="30,30"
                        RowSpacing="0"
                        WidthRequest="60">
                       <Label
                            FontSize="Caption"
                            HorizontalTextAlignment="Center"
                            Text="{Binding Date, StringFormat='{0:ddd}'}"
                            TextColor="{DynamicResource TextColor}"
                            VerticalOptions="End">
                            <Label.Triggers>
                                <DataTrigger
                                    Binding="{Binding IsCurrentDate}"
                                    TargetType="Label"
                                    Value="True">
                                    <Setter Property="TextColor" Value="{DynamicResource OnSurfaceColor}" />
                                </DataTrigger>
                            </Label.Triggers>
                        </Label>
                        <Label
                            Grid.Row="1"
                            FontAttributes="Bold"
                            FontSize="Subtitle"
                            HorizontalTextAlignment="Center"
                            Text="{Binding Date, StringFormat='{0:dd}'}"
                            TextColor="{DynamicResource TextColor}"
                            VerticalOptions="Center">
                            <Label.Triggers>
                                <DataTrigger
                                    Binding="{Binding IsCurrentDate}"
                                    TargetType="Label"
                                    Value="True">
                                    <Setter Property="TextColor" Value="{DynamicResource OnSurfaceColor}" />
                                </DataTrigger>
                            </Label.Triggers>
                        </Label>
                        <controls:CardView.Triggers>
                            <DataTrigger
                                Binding="{Binding IsCurrentDate}"
                                TargetType="controls:CardView"
                                Value="True">
                                <Setter Property="BackgroundColor" Value="{DynamicResource PrimaryColor}" />
                            </DataTrigger>
                            <DataTrigger
                                Binding="{Binding IsCurrentDate}"
                                TargetType="controls:CardView"
                                Value="False">
                                <Setter Property="BackgroundColor" Value="{DynamicResource BackgroundSecondaryColor}" />
                            </DataTrigger>
                        </controls:CardView.Triggers>
                        <controls:CardView.GestureRecognizers>
                            <TapGestureRecognizer Command="{Binding Source={x:Reference this}, Path=CurrentDateCommand}" CommandParameter="{Binding .}" />
                        </controls:CardView.GestureRecognizers>
                    </controls:CardView>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>

代码隐藏

using System.Windows.Input;
namespace App.Controls;
    
    public partial class CalendarView : StackLayout
    {
    #region BindableProperty
        public static readonly BindableProperty CompletedDatesProperty = BindableProperty.Create(
            nameof(CompletedDates),
            typeof(List<DateTime>),
            declaringType: typeof(CalendarView),
            defaultBindingMode: BindingMode.TwoWay,
            defaultValue: new List<DateTime>());
    
        public static readonly BindableProperty SelectedDateProperty = BindableProperty.Create(
            nameof(SelectedDate),
            typeof(DateTime),
            declaringType: typeof(CalendarView),
            defaultBindingMode: BindingMode.TwoWay,
            defaultValue: DateTime.Now,
            propertyChanged: SelectedDatePropertyChanged);
    
        public static readonly BindableProperty SelectedDateCommandProperty = BindableProperty.Create(
            nameof(SelectedDateCommand),
            typeof(ICommand),
            declaringType: typeof(CalendarView));
        #endregion
    
        private static void SelectedDatePropertyChanged(BindableObject bindable, object oldValue, object newValue) 
        {
            var controls  = (CalendarView)bindable;
            if (newValue != null)
            {
                var newDate = (DateTime)newValue;
                if (controls._tempDate.Month == newDate.Month && controls._tempDate.Year == newDate.Year)
                {
                    var currentDate = controls.Dates.Where(_ => _.Date == newDate.Date).FirstOrDefault();
                    if (currentDate != null)
                    {
                        controls.Dates.ToList().ForEach(_ => _.IsCurrentDate = false);
                        currentDate.IsCurrentDate = true;
                    }
                }
                else
                {
                    controls.BindDates(newDate);
    
                }
            }
        }
    
        public List<DateTime> CompletedDates
        {
            get => (List<DateTime>)GetValue(CompletedDatesProperty);
            set => SetValue(CompletedDatesProperty, value);
        }
    
        public DateTime SelectedDate
        {
            get => (DateTime)GetValue(SelectedDateProperty);
            set => SetValue(SelectedDateProperty, value);
        }
    
        public DateTime Today => DateTime.Today;
    
        public ICommand SelectedDateCommand
        {
            get => (ICommand)GetValue(SelectedDateCommandProperty);
            set => SetValue(SelectedDateCommandProperty, value);
        }
    
        public event EventHandler<DateTime> OnDateSelected;
    
    
        private DateTime _tempDate;
    
        public ObservableCollection<CalendarModel> Dates { get; set; } = new ObservableCollection<CalendarModel>();
    
        public CalendarView()
        {
            InitializeComponent();
            BindDates(DateTime.Now);
        }
    
        private void BindDates(DateTime selectedDate)
        {
            Dates.Clear();
            int daysCount = DateTime.DaysInMonth(selectedDate.Year, selectedDate.Month);
    
            for (int day = 1; day <= daysCount; day++)
            {
                Dates.Add(new CalendarModel
                {
                    Date = new DateTime(selectedDate.Year, selectedDate.Month, day),
                    IsCompletedDate = CompletedDates.Any(_ => _.Date.Year == selectedDate.Year && _.Date.Month == selectedDate.Month && _.Date.Day == day)
                });
            }
    
            Dates.FirstOrDefault(_=>_.Date.Date == selectedDate.Date).IsCurrentDate = true;
        }
    
        #region Command
        public ICommand CurrentDateCommand => new Command<CalendarModel>((currentDate) =>
        {
            _tempDate = currentDate.Date;
            SelectedDate = currentDate.Date;
            OnDateSelected?.Invoke(null, currentDate.Date);
            SelectedDateCommand?.Execute(currentDate.Date);
        });
    
        public void ScrollToToday()
        {
            var today = Dates.FirstOrDefault(_ => _.Date.Date == Today.Date);
    
            DateCollectionView.ScrollTo(today, ScrollToPosition.Center);
        }
        #endregion
    
        private void JumpToToday_Button_Clicked(object sender, EventArgs e) => ScrollToToday();
    }

在我的仪表板主页中:

protected override async void OnAppearing()
{
   base.OnAppearing();
   await vm.InitializeAsync();
   calendarView.ScrollToToday();
}

问题: 当应用程序启动并且第一次调用

OnAppearing
时,
CalendarView
滚动到列表末尾,当我导航到另一个选项卡并返回到
DashboardMainPage
时,
CalendarView
按预期滚动到今天。

这里可能会出现什么问题?有什么好的日历视图包可以在毛伊岛使用吗?

When app starts

enter image description here

When navigate on shell tab and back

enter image description here

仪表板主页:

 <controls:CalendarView
     x:Name="calendarView"
     Margin="10"
     CompletedDates="{Binding CompletedDates}" />

代码隐藏

public DashboardMainPage(DashboardMainViewModel vm)
{
    InitializeComponent();
    BindingContext = vm;
}

protected override async void OnAppearing()
{
    base.OnAppearing();
    await vm.InitializeAsync();
   
    calendarView.ScrollToToday();
   
}

在我的仪表板MainViewModel中

public ObservableCollection<DateTime> CompletedDates { get; } = new ObservableCollection<DateTime>();

internal async Task InitializeAsync()
{
    if (IsInitialized)
    {
        return;
    }

    await LoadDataAsync();
}

private async Task LoadDataAsync()
{
    try
    {
        // Set busy indicators
        SetDataLoadingIndicators(true);
        LoadingText = "Loading...";

        // Clear collections
        CompletedDates.Clear();
                    var allForCurrentMonthTask = _unitOfWork.Data.GetAllForCurrentMonthAsync();

   CompletedDates.AddRange(allForCurrentMonthTask.Result.Select(item =>
            new DateTime(item.StartTime.Year, item.StartTime.Month, item.StartTime.Day)));
    }
    catch (Exception ex)
    {
        
    }
    finally
    {
        SetDataLoadingIndicators(false);
    }

    IsInitialized = true;
}

enter image description here

calendar maui .net-maui.shell
© www.soinside.com 2019 - 2024. All rights reserved.