日历视图

日历视图允许用户查看日历并与其交互,日历可以按月、年或十年导航。 用户可以选择单个日期或日期范围。 它没有选取器图面,日历始终可见。

这是正确的控件吗?

使用日历视图允许用户从始终可见的日历中选择单个日期或日期范围。

如果需要让用户一次选择多个日期,则必须使用日历视图。 如果需要让用户仅选取单个日期并且不需要日历始终可见,请考虑使用日历日期选取器日期选取器控件。

有关选择正确控件的详细信息,请参阅 日期和时间控件 文章。

示例

日历视图由 3 个单独的视图组成:月视图、年份视图和十年视图。 默认情况下,它从月份视图打开开始。 可以通过设置 DisplayMode 属性来指定启动视图。

日历视图的 3 个视图

用户单击月份视图中的标题以打开年份视图,然后单击年份视图中的标题以打开十年视图。 用户选取十年视图中的年份以返回到年份视图,并在年份视图中选取一个月以返回到月份视图。 标题一侧的两个箭头按月、按年或十年向前或向后导航。

UWP 和 WinUI 2

重要

本文中的信息和示例是针对使用 Windows App SDKWinUI 3 的应用优化的,但通常适用于使用 WinUI 2 的 UWP 应用。 有关特定于平台的信息和示例,请查看 UWP API 参考。

本部分包含在 UWP 或 WinUI 2 应用中使用该控件所需的信息。

此控件的 API 存在于 Windows.UI.Xaml.Controls 命名空间中。

建议使用最新的 WinUI 2 来获取所有控件的最新样式和模板。 WinUI 2.2 或更高版本包含此控件的使用圆角的新模板。 有关详细信息,请参阅圆角半径

创建日历视图

WinUI 3 库应用包括大多数 WinUI 3 控件、特性和功能的交互式示例。 通过 Microsoft Store 获取应用,或在 GitHub 上获取源代码

此示例演示如何创建简单的日历视图。

<CalendarView/>

生成的日历视图如下所示:

日历视图示例

选择日期

默认情况下,SelectionMode 属性设置为 Single。 这允许用户在日历中选取单个日期。 将 SelectionMode 设置为 “无 ”以禁用日期选择。

将 SelectionMode 设置为 Multiple 以允许用户选择多个日期。 可通过将 DateTime/DateTimeOffset 对象添加到 SelectedDates 集合来以编程方式选择多个日期,如下所示:

calendarView1.SelectedDates.Add(DateTimeOffset.Now);
calendarView1.SelectedDates.Add(new DateTime(1977, 1, 5));

用户可以通过单击或点击日历网格中的日期来取消选择所选日期。

可以处理 SelectedDatesChanged 事件,以在 SelectedDates 集合发生更改时收到通知。

注意

有关日期值的重要信息,请参阅 日期和时间控件文章中的 DateTime 和 Calendar 值

自定义日历视图的外观

日历视图由 ControlTemplate 中定义的 XAML 元素和由控件直接呈现的视觉元素组成。

  • 控件模板中定义的 XAML 元素包括将控件、标题、上一个和下一个按钮和 DayOfWeek 元素括起来的边框。 可以像任何 XAML 控件一样设置这些元素的样式和重新模板化。
  • 日历网格由 CalendarViewDayItem 对象组成。 无法设置这些元素的样式或重新为它们制定模板,但可使用提供的各种属性自定义它们的外观。

此图显示了构成日历月视图的元素。 有关详细信息,请参阅 CalendarViewDayItem 类上的备注。

日历月视图的元素

此表列出了可更改以修改日历元素外观的属性。

元素 属性
DayOfWeek DayOfWeekFormat
CalendarItem CalendarItemBackgroundCalendarItemBorderBrushCalendarItemBorderThicknessCalendarItemForeground
DayItem DayItemFontFamilyDayItemFontSizeDayItemFontStyleDayItemFontWeightHorizontalDayItemAlignment、VerticalDayItemAlignmentCalendarViewDayItemStyle
MonthYearItem (年份和十年视图,相当于 DayItem) MonthYearItemFontFamilyMonthYearItemFontSizeMonthYearItemFontStyleMonthYearItemFontWeight
FirstOfMonthLabel FirstOfMonthLabelFontFamilyFirstOfMonthLabelFontSizeFirstOfMonthLabelFontStyleFirstOfMonthLabelFontWeight、HorizontalFirstOfMonthLabelAlignmentVerticalFirstOfMonthLabelAlignment、IsGroupLabelVisible
FirstofYearDecadeLabel(年份和十年视图,相当于 FirstOfMonthLabel) FirstOfYearDecadeLabelFontFamilyFirstOfYearDecadeLabelFontSizeFirstOfYearDecadeLabelFontStyleFirstOfYearDecadeLabelFontWeight
视觉状态边框 FocusBorderBrush、HoverBorderBrushPressedBorderBrushSelectedBorderBrush、SelectedForegroundSelectedHoverBorderBrushSelectedPressedBorderBrush
OutofScope IsOutOfScopeEnabledOutOfScopeBackgroundOutOfScopeForeground
Today IsTodayHighlightedTodayFontWeightTodayForeground

默认情况下,月视图一次显示 6 周。 可以通过设置 NumberOfWeeksInView 属性来更改显示的周数。 要显示的最小周数为 2;最大值为 8。

默认情况下,年份和十年视图显示在 4x4 网格中。 若要更改行数或列数,请使用所需的行数和列数调用 SetYearDecadeDisplayDimensions 。 这将更改年份和十年视图的网格。

在这里,年份和十年视图将显示在 3x4 网格中。

calendarView1.SetYearDecadeDisplayDimensions(3, 4);

默认情况下,日历视图中显示的最小日期是当前日期之前的 100 年,显示的最大日期是当前日期之前的 100 年。 可以通过设置 MinDate 和 MaxDate 属性来更改日历显示的最小和最大日期。

calendarView1.MinDate = new DateTime(2000, 1, 1);
calendarView1.MaxDate = new DateTime(2099, 12, 31);

更新日历日项目

日历中的每一天都由 CalendarViewDayItem 对象表示。 若要访问单个日期项并使用其属性和方法,请处理 CalendarViewDayItemChanging 事件,并使用事件参数的 Item 属性访问 CalendarViewDayItem。

通过将某个日期的 CalendarViewDayItem.IsBlackout 属性设置为 true,可使该日期无法选择。

可以通过调用 CalendarViewDayItem.SetDensityColors 方法显示有关某一天事件密度的 上下文信息。 每天可以显示 0 到 10 个密度条,并设置每个条的颜色。

以下是日历中的一些日期项。 第 1 天和第 2 天被黑了。第 2 天、3 天和 4 天设置了各种密度条。

具有密度条的日历日

分阶段呈现

日历视图可以包含大量 CalendarViewDayItem 对象。 若要使 UI 保持响应并启用日历的平滑导航,日历视图支持分阶段呈现。 这使你可以将一天项的处理分解为阶段。 如果在完成所有阶段之前将一天移出视图,则不再使用任何时间尝试处理和呈现该项目。

此示例演示了计划约会的日历视图的分阶段呈现。

  • 在第 0 阶段中,呈现默认的日期项。
  • 在第 1 阶段中,将阻止无法预订的日期。 这包括已完全预订的过去日期、星期日和日期。
  • 在第 2 阶段,检查当天预订的每个约会。 将显示每个已确认约会的绿色密度条,以及每个暂定约会的蓝色密度条。

Bookings此示例中的类来自虚构的约会预订应用,并且未显示。

<CalendarView CalendarViewDayItemChanging="CalendarView_CalendarViewDayItemChanging"/>
private void CalendarView_CalendarViewDayItemChanging(CalendarView sender,
                                   CalendarViewDayItemChangingEventArgs args)
{
    // Render basic day items.
    if (args.Phase == 0)
    {
        // Register callback for next phase.
        args.RegisterUpdateCallback(CalendarView_CalendarViewDayItemChanging);
    }
    // Set blackout dates.
    else if (args.Phase == 1)
    {
        // Blackout dates in the past, Sundays, and dates that are fully booked.
        if (args.Item.Date < DateTimeOffset.Now ||
            args.Item.Date.DayOfWeek == DayOfWeek.Sunday ||
            Bookings.HasOpenings(args.Item.Date) == false)
        {
            args.Item.IsBlackout = true;
        }
        // Register callback for next phase.
        args.RegisterUpdateCallback(CalendarView_CalendarViewDayItemChanging);
    }
    // Set density bars.
    else if (args.Phase == 2)
    {
        // Avoid unnecessary processing.
        // You don't need to set bars on past dates or Sundays.
        if (args.Item.Date > DateTimeOffset.Now &&
            args.Item.Date.DayOfWeek != DayOfWeek.Sunday)
        {
            // Get bookings for the date being rendered.
            var currentBookings = Bookings.GetBookings(args.Item.Date);

            List<Color> densityColors = new List<Color>();
            // Set a density bar color for each of the days bookings.
            // It's assumed that there can't be more than 10 bookings in a day. Otherwise,
            // further processing is needed to fit within the max of 10 density bars.
            foreach (booking in currentBookings)
            {
                if (booking.IsConfirmed == true)
                {
                    densityColors.Add(Colors.Green);
                }
                else
                {
                    densityColors.Add(Colors.Blue);
                }
            }
            args.Item.SetDensityColors(densityColors);
        }
    }
}

获取示例代码