WPF配有一个控件,可以立即展示完整日历。这是如此的简单,你只要去放它到你的Window窗体中,就能获得完整的日历视图,像这样:
<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>
注意现在你如何通过选中月来获取完整的日期列表,包括使用空间顶部的箭头跳转到过去和接下来的月份的可能性。除非你设置一个具体日期,当前将会被显示,当前日期将会被标记选中。
你可能会从我们第一个例子注意到Calendar 没有占满全部可用空间。事实上,即使你给它一个大宽度和大高度,实际Calendar 部分仍然只会占用你在屏幕截图上看到的空间量。然后如果你设置两者的值非常小,Calendar 只会部分可见。
这个固定大小的行为并不是典型的WPF,在WPF中,事物通常是会拉伸以填充可用空间,如果你已经给calendar 设计可用空间量和想要让calendar 填充,那么使用它有点麻烦。对于我们幸运的是,所有东西在WPF中都可伸缩的,但是对于例子中的Calendar 空间,它需要许多帮助。我们将使用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>
注意Calendar 控件现在如何扩展到使用宽度的所有可用空间。缩放是在控件所有部分执行的,包括字体大小和边框宽度。
你可能也会注意到Calendar 控件没有用完所有可用高度的空间。这是显而易见的,因为Window窗体高高于宽度,在默认情况下,Viewbox 会在保持原始宽高比的同时拉伸。你能够容易去在两个方向上填充所有空间,简单地改变Stretch属性,从默认的Uniform设为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>
现在它在两个方向上填充所有可用空间。这通常不是最优的选择,因为大多数控件,特别是这一个,如果得到一组不正常的尺寸,例如800像素的高和300像素的宽。看起来会很奇怪,通常的做法是Stretch模式设为Uniform(或者 省略,因为它是默认值)
我会推荐包含进StretchDirection属性的做法,在这个例子所见到的,它允许我们去指定内容应该只被扩展或者缩小,这非常好用。例如,Calendar 控件在特定大小以下变得毫无用处,你将无法看到它是什么,然后为了纠正,你能够设置StretchDirection属性值为UpOnly,Calendar 控件将不再被缩放到低于默认大小。
Calendar 控件将展示默认当前月份,但是你可以通过改变DisplayDate属性去改变。简单地设置它的值为你希望开始的月份内的日期,然后它将反映在控件中:
<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>
SelectionMode非常有趣。通过改变它的默认值SingleDate,你能够选中多个日期或者日期范围。这是一个例子:
<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>
在SingleRange选中模式中,你能够选中整个日期范围,通过保持按下鼠标左键和拖拽一个日期到另外一个,或者通过保持Ctrl或者Shift键的同时点击几个日期,很像多选在Window所有部分都有效。在截图上,我选了一整周,从星期日到星期一,但是你能够轻松的选中一周中的日期和能够扩展到一周的日期范围。
SingleRange模式只允许单个日期范围被选中的方式,就像名字暗示那样。这意味着你不能选中两个彼此不相邻的日期,然后你不能选中超过一个范围。如果你想要这样,你应该切换为MultipleRange 选中模式:
<Calendar SelectionMode="MultipleRange" />
有了这个属性,你可以选中这些日期而没有限制。在这种情况下,我选中了全部的星期六,全部的星期日和几个工作日。
当然,如果你不想要能够选中一个或几个日期,你能够设置SelectionMode的值为None。
现在让我们来讨论如何使用Calendar 控件的选中日期吧!
如果只允许单选(请参阅上面有关选中模式说明),则只需SelectedDate属性。它将允许你同时设置和得到当前选中日期,从Code-behind和通过一个数据绑定。
这里有个我们从Code-behind设置选中日期为明天和使用一个数据绑定去读取选中日期到TextBox 控件的例子:
<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);
}
}
}
在Code-behind,中,我们简单设置SelectedDate属性为当前日期加一天,也就是明天。用户能够通过点击Calendar 控件来改变这个,然后通过在TextBox的Text 属性建立数据绑定,这个改变将会自动被反映。
作为一个额外的奖励,通过数据绑定的魔力,你能够在只需输入一个正确的日期,立即反映为Calendar 控件的改变的同时,也改变了TextBox 的值。如果你输入错误的日期,自动绑定验证会提示你出错:
如果你允许同时选中超过一个日期,你将发现SelectedDate 不那么好用,而你应该使用SelectedDates,它是一个在Calendar 控件当前选中日期的集合。这个属性能够在Code-behind访问或者使用一个绑定,像我们这里做的:
<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>
用这样的一个简单的绑定,我们现在能够展示一个当前选中日期的列表。
如果你想要去从Code-behind反映日期被改变,你能够订阅Calendar 控件的SelectedDatesChanged事件。
根据你使用了Calendar 控件的目的,你可能想要去删掉某些日期。这可能是相关的,例如,在一个预定应用中,你想要去防止已经被预定的日期被选中。Calendar 控件通过使用BlackoutDates集合支持这个开箱即用的功能,当然,你能够同时在XAML 和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)));
}
}
}
在这个例子中,我演示两种添加删除我们日期的方法,通过XAML 和通过Code-behind。两种方法都通过添加CalendarDateRange的实例到BlackedoutDates集合
在XAML,我正在硬编码日期范围(主要展示你也可以通过该方法来做),而我Code-behind做了更聪明的事,通过首先用一个叫AddDatesInPast()方法添加所有排除的日期到集合,然后添加一个今天和明天的范围组合。
DisplayMode属性能够将Calendar 控件从一个你能选中一个日期的位置更改为到你能够选中一个月甚至一年的位置,这是能通过DisplayMode 做到,该属性默认为月份,我们已经在之前的例子中都使用到了。这是我们改变后的样子:
<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>
通过设置DisplayMode为Year,,我们现在能够选中给定年份的一个月了,你能够通过在顶部的箭头改变年份
Calendar 也允许使用DisplayMode属性的Decade值来选中一整年
<Calendar DisplayMode="Decade" />
如你所见,Calendar 控件是个非常通用的控件,具有许多选项和功能,只需要很少的配置就能使用。如果你正在构建一个具有任何与日期相关功能的应用,你将会可能能够以某种方式使用到Calendar 控件。