How to customize holiday appearance in the Silverlight Calendar [Jason Cooke]

Jason Cooke works as a software tester for the AppFx group at Microsoft, where he's has been responsible for testing the Calendar and DatePicker controls.

When started learning about the Silverlight SDK Calendar control, I was convinced that it needed to expose a callback mechanism to let users customize the look of the day buttons. The main scenario I had in mind was making holidays look special. Since then, I realized that this is exactly the sort of scenario that Silverlight data binding/value converters were made for. You can see the final result at https://jrcooke.members.winisp.net/share/CustomizedHolidaysDemo/default.html.

Each day button in the calendar has its DataContext set to the date that the button represents. To implement my scenario, I used data binding with a value converter (which holds the "callback" logic) to connect the button's date with the button's background color.

I used Blend to yank almost everything out of the default CalendarDayButton template, to get the simplest XAML that demonstrates the data binding. The part I added was the binding with my custom BackgroundConverter class, which determines how to convert dates to colors. (In a real app, it would be better to simply add the binding to the default template, to take advantage of everything already there.)

<UserControl x:Class="CustomizedHolidays.Page"
 xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:ext="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
 xmlns:prim="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls"
 xmlns:local="clr-namespace:CustomizedHolidays">
 <UserControl.Resources>
  <local:BackgroundConverter x:Key="BackgroundConverter" />
  <Style x:Key="CalendarDayButtonStyle1" TargetType="prim:CalendarDayButton">
   <Setter Property="Template">
    <Setter.Value>
     <ControlTemplate TargetType="prim:CalendarDayButton">
      <Grid Background=
          "{Binding Converter={StaticResource BackgroundConverter}, Path=Date}">
       <ContentControl x:Name="Content" Margin="5,1,5,1"
          Content="{TemplateBinding Content}" />
      </Grid>
     </ControlTemplate>
    </Setter.Value>
   </Setter>
  </Style>
 </UserControl.Resources>
 <Grid x:Name="LayoutRoot" Background="White">
  <ext:Calendar CalendarDayButtonStyle="{StaticResource CalendarDayButtonStyle1}" />
 </Grid>

</UserControl>

My BackgroundConverter class implements IValueConverter, the only interface that a converter is required to have. My Convert implementation ignores most of the parameters, using only the value (the date from the data binding source) to determine which color to return. (The ConvertBack method is only used in two-way binding, and not used in this example).

public class BackgroundConverter
    : System.Windows.Data.IValueConverter
{
    public static IList<DateTime> Holidays { get; set; }
 
    public object Convert( object value,
                        Type targetType,
                        object parameter,
                        System.Globalization.CultureInfo culture)
    {
        DateTime date = (DateTime)value;
        if (date.DayOfWeek == DayOfWeek.Sunday ||
                    (Holidays != null && Holidays.Contains(date)))
            return new SolidColorBrush(Colors.Orange);
        else
            return new SolidColorBrush(Colors.White);
    }
 
    public object ConvertBack(object value, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

When used without initialization, the BackgroundConverter marks every Sundays as a holiday. You can add more holidays by setting the Holidays property, like in the example below where I add the 2009 Federal Holidays.

public Page() 

{
    BackgroundConverter.Holidays = new DateTime[] {
    new DateTime(2009, 1,1), // New Year’s Day
    new DateTime(2009,1, 19), // Birthday of Martin Luther King, Jr.
    new DateTime(2009,2, 16), // Washington’s Birthday
    new DateTime(2009,5, 25), // Memorial Day
    new DateTime(2009,7, 3), // Independence Day
    new DateTime(2009,9, 7), // Labor Day
    new DateTime(2009,10, 12), // Columbus Day
    new DateTime(2009,11, 11), // Veterans Day
    new DateTime(2009,11, 26), // Thanksgiving Day
    new DateTime(2009,12, 25 ), // Christmas Day
    };
   
    InitializeComponent();
}

I've deployed an app which uses this code and XAML (based on the full CalendarDayButton template) at https://jrcooke.members.winisp.net/share/CustomizedHolidaysDemo/default.html. I hope you find this code useful, and go on to update it to do more (multiple day types, loading the "special" days dynamically, etc.).

Enjoy your programming,
Jason

(Please note that this code is provided under the Microsoft Public License and is also provided "as is", without warranty of any kind.)

<Editorial Comment>
  What a great post. It is always an honor to be able to post for Jason. Hope everyone enjoys this!
   - Kathy
</Editorial Comment>