我正在我的
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
When navigate on shell tab and back
仪表板主页:
<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;
}