Reader Level:
Articles

Disabling (Black Out) Dates in DatePicker in Silverlight With MVVM

By Santhosh Kumar Jayaraman on February 14, 2012
In this article, we are going to see how to disable dates in a datepicker using the blackoutdates property in Silverlight.
  • 0
  • 0
  • 13294
Download Files:
 

Introduction

Let us take a ticket booking example which is best suited for disabling dates. When I try to book a ticket, I should not be able to book a journey ticket for past dates and the return ticket date should not precede the starting date for the journey ticket.

disableimage.gif

Styles for Calendar

Step 1 : If you use Expression Blend we can easily do the custom styles. The following code is generated from Expression blend and I made a few changes for my project requirements such as color and design.

  • Add New Item->Silverlight Resource Dictionary.

s2.gif

Step 2 : Add the following code in the resource dictionary (styles.xaml).

Code

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
    xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls"     
    xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls">
    <Style x:Key="myCalendarDayButtonStyle" TargetType="primitives:CalendarDayButton">
        <Setter Property="Background" Value="Aqua"/>
        <Setter Property="FontSize" Value="10"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="MinWidth" Value="4"/>
        <Setter Property="MinHeight" Value="4"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="primitives:CalendarDayButton">
                    <Grid Name="path">
                        <vsm:VisualStateManager.VisualStateGroups>
                            <vsm:VisualStateGroup x:Name="CommonStates">
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="0:0:0.1"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="Normal"/>
                                <vsm:VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Opacity" To=".5"/>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Opacity" To=".5"/>
                                    </Storyboard>
                                </vsm:VisualState>|
                                <vsm:VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="Background" Storyboard.TargetProperty="Opacity" To="0"/>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="Content" Storyboard.TargetProperty="Opacity" To=".35"/>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="SelectionStates">|
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="0"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="Unselected"/>
                                <vsm:VisualState x:Name="Selected">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="SelectedBackground" Storyboard.TargetProperty="Opacity" To=".75"/>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="CalendarButtonFocusStates">
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="0"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="CalendarButtonFocused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="CalendarButtonUnfocused">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="FocusVisual" Storyboard.TargetProperty="Visibility">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="ActiveStates">
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="0"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="Active"/>
                                <vsm:VisualState x:Name="Inactive">
                                    <Storyboard>
                                        <ColorAnimation Duration="0" Storyboard.TargetName="ContentBrush" Storyboard.TargetProperty="Color" To="#FF777777"/>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="DayStates">
                                <vsm:VisualStateGroup.Transitions>
                                    <vsm:VisualTransition GeneratedDuration="0"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="RegularDay"/>
                                <vsm:VisualState x:Name="Today">
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                            <vsm:VisualStateGroup x:Name="BlackoutDayStates" >
                                <vsm:VisualStateGroup.Transitions>|
                                    <vsm:VisualTransition GeneratedDuration="0"/>
                                </vsm:VisualStateGroup.Transitions>
                                <vsm:VisualState x:Name="NormalDay">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="BlackoutVisual" Storyboard.TargetProperty="Opacity" To="0"/>
                                        <ColorAnimation Duration="0" Storyboard.TargetName="ContentBrush" Storyboard.TargetProperty="Color" To="Black"/>
                                    </Storyboard>
                                </vsm:VisualState>
                                <vsm:VisualState x:Name="BlackoutDay">
                                    <Storyboard>
                                        <DoubleAnimation Duration="0" Storyboard.TargetName="BlackoutVisual" Storyboard.TargetProperty="Opacity" To=".1"/>
                                        <ColorAnimation Duration="0" Storyboard.TargetName="ContentBrush" Storyboard.TargetProperty="Color" To="#ACACAC"/>
                                    </Storyboard>
                                </vsm:VisualState>
                            </vsm:VisualStateGroup>
                        </vsm:VisualStateManager.VisualStateGroups>
                        <Rectangle x:Name="TodayBackground" Fill="#6DBDD1" RadiusX="1" RadiusY="1" Opacity="0"/>
                        <Rectangle x:Name="SelectedBackground" Fill="{TemplateBinding Background}" RadiusX="1" RadiusY="1" Opacity="0"/>
                        <Rectangle x:Name="Background" Fill="{TemplateBinding Background}" RadiusX="1" RadiusY="1" Opacity="0"/>
                        <ContentControl x:Name="Content" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="5,1,5,1" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" FontSize="{TemplateBinding FontSize}" IsTabStop="False" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}">
                            <ContentControl.Foreground>
                                <SolidColorBrush x:Name="ContentBrush" Color="Black"/>
                            </ContentControl.Foreground>
                        </ContentControl>
                        <Rectangle x:Name="BlackoutVisual"  Stroke="Transparent" StrokeThickness="0" Fill="#F0F0F1" />
                        <Rectangle x:Name="FocusVisual" Stroke="#FF6DBDD1" RadiusX="1" RadiusY="1" IsHitTestVisible="false" Visibility="Collapsed"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="myCalendarStyle" TargetType="controls:Calendar">
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Background" >
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFD3DEE8" Offset="0"/>
                    <GradientStop Color="#FFD3DEE8" Offset="0.16"/>
                    <GradientStop Color="#FFFCFCFD" Offset="0.16"/>
                    <GradientStop Color="#FFFFFFFF" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="BorderBrush"  >
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFA3AEB9" Offset="0"/>
                    <GradientStop Color="#FF8399A9" Offset="0.375"/>
                    <GradientStop Color="#FF718597" Offset="0.375"/>
                    <GradientStop Color="#FF617584" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="controls:Calendar">
                    <StackPanel x:Name="Root" HorizontalAlignment="Center">
                        <primitives:CalendarItem x:Name="CalendarItem" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="CalendarDayButtonStyle" Value="{StaticResource myCalendarDayButtonStyle}"/>
    </Style>
</
ResourceDictionary>

Step 3 :
Now add this resource dictionary to app.xaml.

Code
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="BlackoutDatesSL.App"
             xmlns:style="clr-namespace:BlackoutDatesSL">
    <Application.Resources>
        <ResourceDictionary Source="Styles.xaml"/>
    </Application.Resources>
</
Application>

Step 4 :  Now add the calendar style to datepicker in MainPage.xaml.

Code
<UserControl x:Class="BlackoutDatesSL.MainPage"
    xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:viewmodel="clr-namespace:BlackoutDatesSL"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <viewmodel:ViewModel x:Key="ViewModel"/>
    </UserControl.Resources>
    <Grid DataContext="{Binding Source={StaticResource ViewModel}}" Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="From Date:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"/>
        <TextBlock Text="To Date:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center"/>
        <sdk:DatePicker TabIndex="1"  Grid.Row="0" Grid.Column="1" Width="100" Name="FromDate"
                        SelectedDateChanged="FromDate_SelectedDateChanged" CalendarStyle="{StaticResource myCalendarStyle}"
                        SelectedDate="{Binding FromDate,Mode=TwoWay}"/>
        <sdk:DatePicker TabIndex="2" Grid.Row="1"  Width="100" Grid.Column="1" Name="ToDate"
                        CalendarStyle="{StaticResource myCalendarStyle}"  SelectedDate="{Binding ToDate,Mode=TwoWay}" />
    </Grid>
</
UserControl>\

Step 5 :  Now we have to add the logic for blackout dates.

  • When the page is loading, we should not display past dates in the date picker and after selecting a date, we should disable dates in the ToDate datepicker that precede starting date. The following is the code which will disable dates until yesterday.

Code

FromDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), DateTime.Now.AddDays(-1)));
                 ToDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), DateTime.Now.AddDays(-1)));

And in the selected date changed event of FromDate:

private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
        {
            if (((ViewModel)DataContext).ToDate != null)
            {
                if (((ViewModel)DataContext).ToDate < FromDate.SelectedDate)
                    ((ViewModel)DataContext).ToDate = null;
            }
            this.ToDate.BlackoutDates.Clear();
            this.ToDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), ((DateTime)this.FromDate.SelectedDate).AddDays(-1)));
        }

My complete xaml.cs looks like below.

using
System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace BlackoutDatesSL
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            FromDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), DateTime.Now.AddDays(-1)));
            ToDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), DateTime.Now.AddDays(-1)));
            this.DataContext = LayoutRoot.DataContext;
        }
        private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
        {
            if (((ViewModel)DataContext).ToDate != null)
            {
                if (((ViewModel)DataContext).ToDate < FromDate.SelectedDate)
                    ((ViewModel)DataContext).ToDate = null;
            }
            this.ToDate.BlackoutDates.Clear();
            this.ToDate.BlackoutDates.Add(new CalendarDateRange(new DateTime(), ((DateTime)this.FromDate.SelectedDate).AddDays(-1)));
        }
    }
}

My ViewmodelBase and ViewModel:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace BlackoutDatesSL
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

ViewModel.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace BlackoutDatesSL
{
    public class ViewModel : ViewModelBase
    {
        private DateTime? _fromDate;
        public DateTime? FromDate
        {
            get
            {
                return _fromDate;
            }
            set
            {
                _fromDate = value;
                NotifyPropertyChanged("FromDate");
            }
        }
        private DateTime? _toDate;
        public DateTime? ToDate
        {
            get
            {
                return _toDate;
            }
            set
            {
                _toDate = value;
                NotifyPropertyChanged("ToDate");
            }
        }
    }
}

Step 6 : Now run the application and play with the date controls. I have attached complete source code.

If you find the above article useful, please rate and share the documents with your friends.

Santhosh Kumar Jayaraman

I have been working with Microsoft technologies and am still learning many stuffs in it. I am here to share and learn new things .

COMMENT USING

Trending up