.NET MAUI如何滚动到指定元素?日历加载时聚焦当前日期
.NET MAUI 日历控件需求实现方案
一、实现显示上月1号和下月1号
修改日历数据生成逻辑,确保CalendarModel列表中包含上月1号、当月所有日期和下月1号,同时保持日历为完整的周结构(避免残缺行)。假设你的CalendarModel包含Date(存储具体日期)、IsCurrentMonth(标记是否为当前月)、IsCurrentDay(标记是否为今天)等属性,调整PopulateCalendar方法如下:
public async Task PopulateCalendar() { CalendarModel.Clear(); // 假设CalendarModel是ObservableCollection<CalendarModel> int currentMonth = currentCalendar[0]; int currentYear = currentCalendar[1]; // 获取当前月、上月、下月的关键日期 DateTime currentMonthFirst = new DateTime(currentYear, currentMonth, 1); DateTime currentMonthLast = currentMonthFirst.AddMonths(1).AddDays(-1); DateTime prevMonthFirst = currentMonthFirst.AddMonths(-1); DateTime nextMonthFirst = currentMonthLast.AddDays(1); // 计算日历起始日期:从当前月第一天的前一个周日(或周一,可自行调整)开始,若早于上月1号则从1号开始 int daysBeforeCurrentMonth = (int)currentMonthFirst.DayOfWeek; DateTime startDate = currentMonthFirst.AddDays(-daysBeforeCurrentMonth); if (startDate < prevMonthFirst) startDate = prevMonthFirst; // 添加上月日期(从起始日到上月最后一天) for (DateTime date = startDate; date < currentMonthFirst; date = date.AddDays(1)) { CalendarModel.Add(new CalendarModel { Date = date, DayName = date.ToString("ddd"), DayNumber = date.Day.ToString(), IsCurrentMonth = false, IsCurrentDay = date.Date == DateTime.Today.Date }); } // 添加当前月所有日期 for (DateTime date = currentMonthFirst; date <= currentMonthLast; date = date.AddDays(1)) { CalendarModel.Add(new CalendarModel { Date = date, DayName = date.ToString("ddd"), DayNumber = date.Day.ToString(), IsCurrentMonth = true, IsCurrentDay = date.Date == DateTime.Today.Date }); } // 计算日历结束日期:到当前月最后一天的下一个周六,确保包含下月1号 int daysAfterCurrentMonth = 6 - (int)currentMonthLast.DayOfWeek; DateTime endDate = currentMonthLast.AddDays(daysAfterCurrentMonth); if (endDate < nextMonthFirst) endDate = nextMonthFirst; // 添加下月日期(从下月1号到结束日) for (DateTime date = nextMonthFirst; date <= endDate; date = date.AddDays(1)) { CalendarModel.Add(new CalendarModel { Date = date, DayName = date.ToString("ddd"), DayNumber = date.Day.ToString(), IsCurrentMonth = false, IsCurrentDay = date.Date == DateTime.Today.Date }); } }
二、实现加载新月份时自动滚动到当前日期
方法1:代码后台事件绑定(简单直接)
- 在XAML中给CollectionView命名:
<CollectionView x:Name="CalendarCollectionView" ItemsSource="{Binding CalendarModel}" SelectionMode="None"> <!-- 原有布局内容不变 --> </CollectionView>
- 在ViewModel中添加数据加载完成事件:
public event EventHandler CalendarDataLoaded; public async Task PopulateCalendar() { // 原有数据生成逻辑... // 数据加载完成后触发事件 CalendarDataLoaded?.Invoke(this, EventArgs.Empty); }
- 在页面代码后台(.xaml.cs)订阅事件并执行滚动:
public YourCalendarPage() { InitializeComponent(); if (BindingContext is CalendarViewModel vm) { vm.CalendarDataLoaded += OnCalendarDataLoaded; } } private void OnCalendarDataLoaded(object sender, EventArgs e) { if (BindingContext is CalendarViewModel vm) { // 找到当前日期对应的项 var currentDayItem = vm.CalendarModel.FirstOrDefault(item => item.IsCurrentDay); if (currentDayItem != null) { // 滚动到当前日期,居中显示并带动画 CalendarCollectionView.ScrollTo(currentDayItem, ScrollToPosition.Center, animate: true); } } }
方法2:MVVM行为(符合MVVM规范)
- 创建自定义滚动行为:
using Microsoft.Maui.Controls; public class ScrollToCurrentDayBehavior : Behavior<CollectionView> { public static readonly BindableProperty CurrentDayItemProperty = BindableProperty.Create(nameof(CurrentDayItem), typeof(object), typeof(ScrollToCurrentDayBehavior), null, propertyChanged: OnCurrentDayItemChanged); public object CurrentDayItem { get => GetValue(CurrentDayItemProperty); set => SetValue(CurrentDayItemProperty, value); } private static void OnCurrentDayItemChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is ScrollToCurrentDayBehavior behavior && behavior.AssociatedObject != null && newValue != null) { behavior.AssociatedObject.ScrollTo(newValue, ScrollToPosition.Center, true); } } protected override void OnAttachedTo(CollectionView bindable) { base.OnAttachedTo(bindable); } protected override void OnDetachingFrom(CollectionView bindable) { base.OnDetachingFrom(bindable); } }
- 在XAML中引用行为并绑定属性:
<CollectionView ItemsSource="{Binding CalendarModel}" SelectionMode="None"> <CollectionView.Behaviors> <local:ScrollToCurrentDayBehavior CurrentDayItem="{Binding CurrentDayItem}" /> </CollectionView.Behaviors> <!-- 原有布局内容不变 --> </CollectionView>
- 在ViewModel中添加
CurrentDayItem属性:
private CalendarModel _currentDayItem; public CalendarModel CurrentDayItem { get => _currentDayItem; set => SetProperty(ref _currentDayItem, value); // 依赖CommunityToolkit.Mvvm的ObservableObject } public async Task PopulateCalendar() { // 原有数据生成逻辑... // 设置当前日期项,触发滚动 CurrentDayItem = CalendarModel.FirstOrDefault(item => item.IsCurrentDay); }
三、额外优化
如果需要仅在显示当前月份时滚动到今天,可在ViewModel中添加判断:
var today = DateTime.Today; if (today.Month == currentCalendar[0] && today.Year == currentCalendar[1]) { CurrentDayItem = CalendarModel.FirstOrDefault(item => item.IsCurrentDay); } else { // 切换到非当前月份时,滚动到当前显示月份的第一天 CurrentDayItem = CalendarModel.FirstOrDefault(item => item.IsCurrentMonth && item.Date.Day == 1); }
内容的提问来源于stack exchange,提问作者wenreloz
相关产品推荐
相关产品推荐

