Skip to content

Feat: Add weeknumbers to Calendar#21311

Open
timunie wants to merge 14 commits into
AvaloniaUI:masterfrom
timunie:feat/CalendarWeekNumbers
Open

Feat: Add weeknumbers to Calendar#21311
timunie wants to merge 14 commits into
AvaloniaUI:masterfrom
timunie:feat/CalendarWeekNumbers

Conversation

@timunie
Copy link
Copy Markdown
Collaborator

@timunie timunie commented May 4, 2026

What does the pull request do?

Adds week number display to both Calendar and CalendarDatePicker in month view (Fluent and Simple themes).

Calendar with week numbers

What is the current behavior?

Calendar and CalendarDatePicker only show day-of-week headers and date cells in month view. There is no way to display week numbers alongside the calendar grid.

What is the updated/expected behavior with this PR?

  • A new week-number column can be shown on the left side of the month grid by setting IsWeekNumberVisible="True".
  • The column header is configurable via WeekNumberHeader (e.g. "#", "CW", "KW", "Wk" — defaults to "#").
  • The week numbering rule is configurable via WeekNumberRule using the new CalendarWeekNumberRule enum. Use WeekNumberRule="Iso" for ISO 8601 week numbering; other values (FirstDay, FirstFullWeek, FirstFourDayWeek) map to the BCL equivalents. Defaults to the current culture's rule.
  • All properties are mirrored on CalendarDatePicker, where they propagate to the inner popup calendar.
  • The calendar does not shrink when switching from month view to year/decade view. A new :hasweeknumbers pseudo-class on CalendarItem is used in the Fluent theme to hold the minimum width stable.

How was the solution implemented?

New type — CalendarWeekNumberLabel (Avalonia.Controls.Primitives)

A ContentControl subclass placed in column 0 of PART_MonthView. Exposes a :header pseudo-class for the top cell (row 0) so themes can style it differently from the data cells (rows 1–6).

New enum — CalendarWeekNumberRule (Avalonia.Controls)

Avalonia-specific enum replacing the BCL CalendarWeekRule on the WeekNumberRule property, with an additional Iso value:

public enum CalendarWeekNumberRule
{
    FirstDay = 0,         // maps to CalendarWeekRule.FirstDay
    FirstFullWeek = 1,    // maps to CalendarWeekRule.FirstFullWeek
    FirstFourDayWeek = 2, // maps to CalendarWeekRule.FirstFourDayWeek
    Iso = 3,              // explicit ISO 8601 shorthand
}

API diff

// Avalonia.Controls.Calendar — 3 new properties
+public static readonly StyledProperty<bool> IsWeekNumberVisibleProperty;
+public bool IsWeekNumberVisible { get; set; }                       // default: false

+public static readonly StyledProperty<CalendarWeekNumberRule> WeekNumberRuleProperty;
+public CalendarWeekNumberRule WeekNumberRule { get; set; }          // default: current culture

+public static readonly StyledProperty<object?> WeekNumberHeaderProperty;
+public object? WeekNumberHeader { get; set; }                       // default: "#"


// Avalonia.Controls.CalendarDatePicker — same 3 properties via AddOwner
+public static readonly StyledProperty<bool> IsWeekNumberVisibleProperty;
+public bool IsWeekNumberVisible { get; set; }

+public static readonly StyledProperty<CalendarWeekNumberRule> WeekNumberRuleProperty;
+public CalendarWeekNumberRule WeekNumberRule { get; set; }

+public static readonly StyledProperty<object?> WeekNumberHeaderProperty;
+public object? WeekNumberHeader { get; set; }


// Avalonia.Controls.Primitives.CalendarItem — new pseudo-class
-[PseudoClasses(":calendardisabled")]
+[PseudoClasses(":calendardisabled", ":hasweeknumbers")]


// Avalonia.Controls.Primitives.CalendarWeekNumberLabel — new public type
+public sealed class CalendarWeekNumberLabel : ContentControl
+{
+    public bool IsHeader { get; internal set; }  // sets :header pseudo-class
+}

// Avalonia.Controls/Calendar/DateTimeHelper.cs
+public static int GetWeekOfYear(DateTime date, CalendarWeekNumberRule rule, DayOfWeek firstDayOfWeek)

ISO 8601 week number fix — DateTimeHelper.GetWeekOfYear

.NET's Calendar.GetWeekOfYear with FirstFourDayWeek + Monday incorrectly returns week 53 for late-December dates that ISO 8601 assigns to week 1 of the next year (e.g. 2018-12-31 → ISO week 1 of 2019). Both the Iso shorthand and the explicit FirstFourDayWeek + Monday combination delegate to ISOWeek.GetWeekOfYear to avoid this bug:

public static int GetWeekOfYear(DateTime date, CalendarWeekNumberRule rule, DayOfWeek firstDayOfWeek)
{
    var mappedRule = (System.Globalization.CalendarWeekRule)(int)rule;

    if (rule == CalendarWeekNumberRule.Iso ||
        (mappedRule == CalendarWeekRule.FirstFourDayWeek && firstDayOfWeek == DayOfWeek.Monday))
        return ISOWeek.GetWeekOfYear(date);

    return CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(date, mappedRule, firstDayOfWeek);
}

Checklist

Breaking changes

None.

Obsoletions / Deprecations

None.

Fixed issues

Fixes #7976

@timunie timunie added enhancement needs-api-review The PR adds new public APIs that should be reviewed. labels May 4, 2026
@avaloniaui-bot
Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0065222-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Comment thread src/Avalonia.Controls/Calendar/DateTimeHelper.cs Outdated
@timunie timunie requested a review from Copilot May 6, 2026 15:20
@timunie timunie marked this pull request as ready for review May 6, 2026 15:20
@avaloniaui-bot
Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0065248-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Comment thread src/Avalonia.Controls/Calendar/Calendar.cs Outdated
Comment thread src/Avalonia.Controls/Calendar/CalendarItem.cs Outdated
Comment thread src/Avalonia.Controls/Calendar/CalendarWeekNumberLabel.cs Outdated
Comment thread src/Avalonia.Controls/Calendar/DateTimeHelper.cs Outdated
Comment thread src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.Properties.cs Outdated
Comment on lines +405 to +406
<StaticResource x:Key="CalendarViewWeekNumberSeparatorForeground"
ResourceKey="SystemControlDisabledBaseMediumLowBrush" />
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned above, if the CalendarWeekNumberLabel goes away it would be needed to add CalendarViewWeekNumberForeground and related resources here.

/// the appearance — for example <c>FontWeight="Bold"</c>.
/// Use the <c>:header</c> pseudo-class to target the column header cell (row 0).
/// </summary>
public sealed class CalendarWeekNumberLabel : ContentControl
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO an entire new primitive probably isn't needed for this concept. It can be done with text and light-weight styling resources alone.

That in turn allows room for future expansion in this area. For example -- we might want to make it interactive as a button in some way, the calendar might get a week ONLY view, etc.

I'm also not a fan of the legacy term "Label" being used for new controls. That just isn't done in modern XAML.

Comment thread src/Avalonia.Controls/Calendar/Calendar.cs Outdated
@timunie timunie force-pushed the feat/CalendarWeekNumbers branch from 0e2f4d5 to 49d4f91 Compare May 21, 2026 20:06
@avaloniaui-bot
Copy link
Copy Markdown

You can test this PR using the following package version. 12.1.999-cibuild0065706-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement needs-api-review The PR adds new public APIs that should be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Calendar with week numbers

3 participants