TOC

This article is currently in the process of being translated into Portuguese (~18% done).

Controles diversos:

The Calendar control

O WPF vem com um controle para exibir um calendário completo, pronto para usar. É tão simples que você só precisa colocá-lo dentro de sua janela para ter a vista de um calendário completo, assim:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarControlSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarControlSample" Height="250" Width="300">
    <Grid>
<Calendar />
    </Grid>
</Window>

Repare como você obteve uma lista inteira com as datas do mês selecionado, incluindo a possibilidade de saltar entre meses através das setas para a direita e para a esquerda no topo do controlo. Caso você selecione não uma data específica, o mês atual será mostrado assim como a data atual será marcada por predefinição.

Tamanho do Calendário

Você deve ter reparado que no primeiro exemplo o calendário não ocupa todo o espaço disponível. De facto, mesmo que você aumente a sua altura e largura, o próprio calendário apenas ocupará o espaço que está demonstrado na foto, e se você definir os valores muito pequenos, o calendário apenas estará parcialmente visível.

O comportamento do tamanho fixo não é muito típico do WPF, onde os controles esticam-se para preencher todo o espaço disponível, o que pode ser um pouco frustrante se você tiver designado um certo espaço para o calendário preencher. No entanto, para nós, no WPF tudo é dimensionável, mas no caso do controle do Calendário, ele precisa de um pouco de ajuda. Portanto para este propósito vamos usar o controle ViewBox:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarViewboxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarViewboxSample" Height="350" Width="300">
    <Viewbox>
<Calendar />
    </Viewbox>
</Window>

Repare em como o Calendário se ajusta até ao ponto onde usa todo o espaço disponível na sua largura. O dimensionamento é feito em todas as partes do controle, incluíndo tamanho da fonte e da grossura das bordas.

You will probably also notice that the Calendar control doesn't use up all the available height space. This is noticeable because the window is higher than it is wide and by default, the Viewbox will stretch while maintaining the original aspect ratio. You can easily make it stretch to fill all space in both directions though - simply change the Stretch property from its default Uniform value to Fill:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarViewboxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarViewboxSample" Height="350" Width="300">
    <Viewbox Stretch="Fill" StretchDirection="UpOnly">
<Calendar />
    </Viewbox>
</Window>

Now it takes up all the available space, in both directions. This is generally not preferable though, since most controls, and this one in particular, will look strange if it gets an abnormal set of dimensions, e.g. 800 pixels high and 300 pixels wide. A Stretch mode set to Uniform (or left out, as it is the default) is usually the way to go.

I would recommend including the StretchDirection property though, as seen in this example. It allows us to specify that the contents should only be scaled up or down, which can be useful. For instance, the Calendar control becomes quite useless below a certain size, where you can no longer see what it is, and to avoid that, you can set the StretchDirection to UpOnly - the Calendar control will then no longer be scaled below its default size.

Setting the initial view using DisplayDate

The Calendar control will by default show the current month, but you can change this by using the DisplayDate property. Simply set it to a date within the month you wish to start with and it will be reflected in the control:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarDisplayDateSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarDisplayDateSample" Height="300" Width="300">
    <Viewbox>
<Calendar DisplayDate="01.01.2014" />
    </Viewbox>
</Window>

Calendar SelectionMode

The SelectionMode property is interesting. By changing it from its default value, SingleDate, you can select multiple dates or ranges of dates. Here's an example:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarSelectionModeSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarSelectionModeSample" Height="300" Width="300">
    <Viewbox>
<Calendar SelectionMode="SingleRange" />
    </Viewbox>
</Window>

In the SingleRange SelectionMode, you can select an entire range of dates, either by holding down the left mouse button and dragging from one date to another or by holding down the Ctrl or Shift keys while clicking several dates, much like multi selection works in all parts of Windows. On the screenshot, I've selected an entire week, from Sunday to Monday, but you can just as easily select dates in the middle of the week and ranges which expands a single week.

SingleRange mode only allows a single range of dates to be selected though, much like the name suggests. This means that you can't select two dates which are not next to each other, and you can't select more than one range. If you want this, you should switch to MultipleRange selection:

<Calendar SelectionMode="MultipleRange" />

With this property, there are really no limits to the dates you can select. In this case, I've selected all the Saturdays, all the Sundays and a couple of week days in between.

Of course, if you don't want the ability to select one or several dates, you can set the SelectionMode to None.

Now let's discuss how we can work with the selected date(s) of the Calendar control.

Working with the selected date

The SelectedDate property is all you need if you're only allowing single selections (see the above explanation on selection modes). It allows you to both set and get a currently selected date, from Code-behind as well as through a data binding.

Here's an example where we set the selected date to tomorrow from Code-behind and then use a data binding to read out the selected date to a TextBox control:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarSelectionSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarSelectionSample" Height="280" Width="220">
    <StackPanel Margin="10">
<Calendar Name="cldSample" SelectionMode="MultipleRange" SelectedDate="10.10.2013" />
<Label>Selected date:</Label>
<TextBox Text="{Binding ElementName=cldSample, Path=SelectedDate, StringFormat=d, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>
</Window>
using System;
using System.Windows;

namespace WpfTutorialSamples.Misc_controls
{
    public partial class CalendarSelectionSample : Window
    {
public CalendarSelectionSample()
{
    InitializeComponent();
    cldSample.SelectedDate = DateTime.Now.AddDays(1);
}
    }
}

In Code-behind, we simply set the SelectedDate property to the current date plus one day, meaning tomorrow. The user can then change this selection by clicking in the Calendar control, and through the data binding established in Text property of the TextBox, this change will automatically be reflected there.

As an added bonus, through the magic of data binding, you can also change the value from the TextBox - just input a valid date and the change will be immediately reflected in the Calendar control. Should you enter a bad date, the automatic binding validation notifies you of the problem:

Working with multiple selected dates

If you allow more than one selected date at the time, you won't find the SelectedDate property that useful. Instead, you should use the SelectedDates, which is a collection of currently selected dates in the Calendar control. This property can be accessed from Code-behind or used with a binding, like we do here:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarSelectedDatesSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarSelectedDatesSample" Height="420" Width="220">
    <StackPanel Margin="10">
<Calendar Name="cldSample" SelectionMode="MultipleRange" />
<Label>Selected dates:</Label>
<ListBox ItemsSource="{Binding ElementName=cldSample, Path=SelectedDates}" MinHeight="150" />
    </StackPanel>
</Window>

With a simple binding like that, we're now able to display a list of the currently selected dates.

If you want to react to dates being changed from Code-behind, you can subscribe to the SelectedDatesChanged event of the Calendar control.

Blackout dates

Depending on what you use the Calendar control for, you may want to black out certain dates. This could be relevant e.g. in a booking application, where you want to prevent already reserved dates from being selected. The Calendar control supports this right out of the box through the use of the BlackoutDates collection, which you can of course use from both XAML and Code-behind:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarBlockedoutDatesSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarBlockedoutDatesSample" Height="300" Width="300">
    <Viewbox>
<Calendar Name="cldSample" SelectionMode="MultipleRange">
    <Calendar.BlackoutDates>
<CalendarDateRange Start="10.13.2013" End="10.19.2013" />
<CalendarDateRange Start="10.27.2013" End="10.31.2013" />
    </Calendar.BlackoutDates>
</Calendar>
    </Viewbox>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;

namespace WpfTutorialSamples.Misc_controls
{
    public partial class CalendarBlockedoutDatesSample : Window
    {
public CalendarBlockedoutDatesSample()
{
    InitializeComponent();
    cldSample.BlackoutDates.AddDatesInPast();
    cldSample.BlackoutDates.Add(new CalendarDateRange(DateTime.Today, DateTime.Today.AddDays(1)));
}
    }
}

In this example, I demonstrate both ways of adding blacked out dates - through XAML and through Code-behind. Both ways works by adding instances of CalendarDateRange to the BlackedoutDates collection.

In XAML, I'm hardcoding the date ranges (mostly to show you it can be done that way too), while I do something a bit more clever in Code-behind, by first adding all past dates to the collection with a single call to the AddDatesInPast() method and then adding a range consisting of today and tomorrow.

DisplayMode - showing months or years

The DisplayMode property can change the Calendar control from a place where you can select a date to a place where you can select a month or even a year. This is done through the DisplayMode property, which defaults to Month, which we've used in all the previous examples. Here's how it looks if we change it:

<Window x:Class="WpfTutorialSamples.Misc_controls.CalendarDisplayModeSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CalendarDisplayModeSample" Height="300" Width="300">
    <Viewbox>
<Calendar DisplayMode="Year" />
    </Viewbox>
</Window>

By setting the DisplayMode to Year, we can now select a month of a given year. You can change the year in the top, by using the arrows.

The Calendar control also allows for selecting an entire year, by using the Decade value for the DisplayMode property:

<Calendar DisplayMode="Decade" />

Summary

As you can see, the Calendar control is a very versatile control with lots of options and functionality, requiring only a minimum of configuration to use. If you're building an application with any sort of date-related functionality, you will probably be able to use the Calendar control, one way or another.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!