Calendar Density Coloring

Enhancing CalendarView with Stripes, Tooltips, and Smarter Visuals in WinUI3

Screenshot of CustomCalendarView in action

👉 Code Files:


Introduction

So, you’ve landed on my unknown blog site. That already tells me something about you: you’re tired. You’ve been clicking around StackOverflow, GitHub issues, blog posts, even ChatGPT can't help, and now you’ve ended up here.

And I know what you’re thinking:

“Please, internet stranger, I don’t want to read an essay. Just give me the code.”

Okay. Fair. I respect that. That’s why I linked the code above the fold 👆. But… if you’re still scrolling, maybe you’re slightly curious what this code actually does.


What’s in the Box?

We’re building a Custom CalendarView control in WinUI 3 that:

So basically: it’s a calendar that’s smarter than the default one, and prettier than your Outlook reminders.


The XAML

<UserControl x:Class="MyNamespace.CustomCalendarView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             ScrollViewer.HorizontalScrollMode="Disabled"
             ScrollViewer.VerticalScrollBarVisibility="Disabled">
    <CalendarView x:Name="calendarView"
                  NumberOfWeeksInView="5"
                  Margin="0"
                  SelectionMode="Single"
                  ScrollViewer.HorizontalScrollMode="Disabled"
                  ScrollViewer.VerticalScrollBarVisibility="Disabled" />
</UserControl>

That’s it. Nothing magical here. We’re just wrapping a CalendarView inside a UserControl, because we’re about to supercharge it with some C#.


The C# Code (The Real Party)

Let’s break down the important parts.

1. Dependency Properties

We’ve got two:

Think of AppointmentsData as your calendar’s brain. It knows which days are busy and which days are empty like your social life during exam season.

2. Constructor Magic

public CustomCalendarView()
{
    InitializeComponent();
    SelectedDate = DateTime.Now;

    calendarView.SelectedDates.Add(SelectedDate.Date);
    calendarView.SelectedDatesChanged += CalendarView_SelectedDatesChanged;
    calendarView.CalendarViewDayItemChanging += CalendarView_CalendarViewDayItemChanging;
    calendarView.ActualThemeChanged += CalendarView_ActualThemeChanged;
}

Here we:

3. Tooltips for Humans

private void AddToolTip(CalendarViewDayItem item, int count)
{
    string tooltipText = $"{count} {(count == 1 ? "Appointment" : "Appointments")}\r\n{dayLabel}";
    ToolTipService.SetToolTip(item, new ToolTip
    {
        Content = tooltipText,
        Placement = PlacementMode.Mouse
    });
}

This makes hovering over a day actually useful. Instead of just seeing a date, you’ll see:

4. Appointment Density Coloring

private static IEnumerable<Windows.UI.Color> GetDensityColors(int count)
{
    int cappedCount = Math.Min(10, count);
    Windows.UI.Color[] colors = new Windows.UI.Color[cappedCount];
    for (int i = 0; i < cappedCount; i++)
    {
        colors[i] = DensityColor;
    }
    return colors;
}

More appointments → more stripes. Max 10 stripes, because otherwise your calendar would look like a barcode. Color is a nice semi-transparent for theme switching.

5. Applying Tooltips and Colors

private void ApplyToolTipsAndColors()
{
    foreach (var item in FindVisualChildren<CalendarViewDayItem>(calendarView))
    {
        if (AppointmentsData.TryGetValue(item.Date.Date, out int count) && count > 0)
        {
            AddToolTip(item, count);
        }
        else
        {
            ToolTipService.SetToolTip(item, null);
        }
    }
}

This goes through all days in the calendar and updates them. Think of it as the makeup artist for your CalendarView.


Example Usage

<controls:CustomCalendarView AppointmentsData="{x:Bind AppointmentsData}"
                             SelectedDate="{x:Bind CurrentDate, Mode=TwoWay}" />

var today = DateTime.Now.Date;
AppointmentsData = new Dictionary<DateTime, int>();

for (int i = -3650; i <= 1825; i++) // 10 years back, 5 years forward
{
    var date = today.AddDays(i);
    AppointmentsData[date] = Random.Shared.Next(0, 25);
}

This example fills 15 years of data with random appointment counts.

Now go forth and make your calendars so colorful.

⬅ Previous: Control Lifecycle - Event Sequence
Next: WinUI Gallery 2.7 ➡
decorative gif