Поделиться через


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>

Comments

  • Anonymous
    May 18, 2009
    How to customize holiday appearance in the Silverlight Calendar [Jason Cooke] こんな方法があるんですねぇ。 おもしろいなぁ...

  • Anonymous
    May 19, 2009
    Thank you for submitting this cool story - Trackback from DotNetShoutout

  • Anonymous
    October 04, 2009
    Great, thx! btw, how could you add a control/user control into a calendar cell

  • Anonymous
    January 27, 2010
    I've implemented what you've gone over here in this tutorial however after doing so I've lost mouseover highlighting and the coloring of the selected date.  How did you get these working again in the demo link?  I've tried debugging in the convert function and nothing looks like it comes with enough data to be of any use.

  • Anonymous
    April 10, 2010
    Great work, but I have a question. I'm making a scheduler and need to highlight the date when such date is scheduled. When a new schedule entered, I would update the Ilist in the background converter, however, the calendar will not refresh until I click on it. I tried the UpdateLayout(), ApplyTemplate() without sucess, Any idea to refresh the calendar without the user having to click on it.

  • Anonymous
    April 28, 2010
    Thank you for your post. It is a good post. <a href="http://www.bolcroatia.com">Bol Apartments</a>

  • Anonymous
    June 28, 2010
    I have the same problem of Benny, any reply ? Your demo semms to work so ...

  • Anonymous
    August 02, 2010
    I have the same problem as Benny. Any solution yet? Thanks.