在 WPF Calendar 中高亮显示日期





5.00/5 (9投票s)
在 WPF Calendar 中高亮和标记单个日期
介绍
我希望使用 WPF 日历并突出显示和标记感兴趣的单个日期。我在网上搜索,但找不到任何可用的解决方案。我找到了微软的“RedLetterDays”:http://msdn.microsoft.com/en-us/magazine/dd882520.aspx#id0430067,但它只能与 WPF Toolkit 一起工作,而且可配置性不高。这个解决方案不依赖于修改日历,而是修改背景。
使用代码
使用这段代码非常简单,分为四个步骤:
- 设置日历
- 设置图标
- 设置日期
- 更改日期时更新背景
XAML 部分不过是一个基本的日历。
<Grid>
<Calendar Name="Kalender" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top"/>
</Grid>
CalendarBackground
在类中声明。背景类使用对 Calendar
类的引用进行初始化。这样做是为了能够访问 DisplayDate
。
private readonly CalenderBackground background;
background = new CalenderBackground(Kalender);
首先,您必须配置要在背景中使用的图标。AddOverlay
使用 ID 和图像的文件名调用。图像尺寸为 21x16 像素,背景透明。日历中行之间的间距在 15 到 16 像素之间。
background.AddOverlay("circle", "circle.png");
background.AddOverlay("tjek", "tjek.png");
background.AddOverlay("cross", "cross.png");
background.AddOverlay("box", "box.png");
background.AddOverlay("gray", "gray.png");
接下来,您可以添加日期和要在该日期上显示的图像的 ID。可以将多个图标添加到同一日期。叠加是半透明的,因此即使堆叠在一起,图标也能可见。
background.AddDate(new DateTime(2013, 02, 20), "tjek");
background.AddDate(new DateTime(2013, 02, 17), "tjek");
background.AddDate(new DateTime(2013, 02, 12), "tjek");
background.AddDate(new DateTime(2013, 02, 13), "tjek");
background.AddDate(new DateTime(2013, 02, 14), "tjek");
background.AddDate(new DateTime(2013, 02, 15), "tjek");
background.AddDate(new DateTime(2013, 02, 15), "circle");
background.AddDate(new DateTime(2013, 03, 01), "circle");
background.AddDate(new DateTime(2013, 03, 02), "circle");
background.AddDate(new DateTime(2013, 02, 10), "cross");
如果您愿意,可以设置一个选项来标记周末。
background.grayoutweekends = "gray";
将类的输出分配为日历的背景。创建一个 DisplayDateChanged
事件处理程序来处理日历中更改日期时更新背景。
Kalender.Background = background.GetBackground();
// Update background when changing the shown month
Kalender.DisplayDateChanged += KalenderOnDisplayDateChanged;
private void KalenderOnDisplayDateChanged(object sender, CalendarDateChangedEventArgs calendarDateChangedEventArgs)
{
Kalender.Background = background.GetBackground();
}
真正的“魔术”发生在 CalenderBackground
类中。
首先,我必须计算显示的第一个日期(如上面的屏幕截图中的 1 月 28 日)。代码将星期一和星期日作为一周的第一天处理。由于我知道月份的第一天是星期几,因此我可以计算出第一个显示的日期是哪一天。
DateTime displaydate = _calendar.DisplayDate;
var firstdayofmonth = new DateTime(displaydate.Year, displaydate.Month, 1);
var dayofweek = (int) firstdayofmonth.DayOfWeek;
if (dayofweek == 0) dayofweek = 7; // set sunday to day 7.
if (dayofweek == (int)_calendar.FirstDayOfWeek) dayofweek = 8; // show a whole week ahead
if (_calendar.FirstDayOfWeek == DayOfWeek.Sunday) dayofweek += 1;
DateTime firstdate = firstdayofmonth.AddDays(-((Double) dayofweek) + 1);
我创建一个默认背景,在月份/年份后面添加阴影。
var rtBitmap = new RenderTargetBitmap( 178 /* PixelWidth */, 160 /* PixelHeight */,
96 /* DpiX */, 96 /* DpiY */, PixelFormats.Default);
var drawVisual = new DrawingVisual();
using (DrawingContext dc = drawVisual.RenderOpen())
{
var backGroundBrush = new LinearGradientBrush();
backGroundBrush.StartPoint = new Point(0.5, 0);
backGroundBrush.EndPoint = new Point(0.5, 1);
backGroundBrush.GradientStops.Add(new GradientStop((Color) ColorConverter.ConvertFromString ("#FFE4EAF0"), 0.0));
backGroundBrush.GradientStops.Add(new GradientStop((Color) ColorConverter.ConvertFromString ("#FFECF0F4"), 0.16));
backGroundBrush.GradientStops.Add(new GradientStop((Color) ColorConverter.ConvertFromString ("#FFFCFCFD"), 0.16));
backGroundBrush.GradientStops.Add(new GradientStop((Color) ColorConverter.ConvertFromString ("#FFFFFFFF"), 1));
dc.DrawRectangle(backGroundBrush, null, new Rect(0, 0, rtBitmap.Width, rtBitmap.Height));
}
rtBitmap.Render(drawVisual);
最后也是最重要的部分,遍历日历的 7 列和 6 行。由于我知道显示的第一个日期,我可以遍历日期,并且当我在“datelist”中找到匹配项时,可以在计算出的位置添加叠加。这是通过绘制包含叠加内容的矩形来完成的。
using (DrawingContext dc = drawVisual.RenderOpen())
{
for (int y = 0; y < 6; y++)
for (int x = 0; x < 7; x++)
{
int xpos = x*21 + 17;
int ypos = y*16 + 50;
foreach (string overlayid in datelist.Where(c => c.date == firstdate).Select(c => c.overlay))
{
if (overlayid != null)
{
overlay overlay = overlays.Where(c => c.id == overlayid).FirstOrDefault();
dc.DrawRectangle(overlay.Brush, null /* no pen */,
new Rect(xpos, ypos, overlay.BitMap.Width, overlay.BitMap.Height));
}
}
firstdate = firstdate.AddDays(1);
}
}
rtBitmap.Render(drawVisual);
var brush = new ImageBrush(rtBitmap); // create a brush using the BitMap
return brush;
完成了。一种轻松创建自定义日历的方法。
未来改进
一个不错的特性是添加鼠标悬停提示,解释为什么突出显示该日期。
历史
- 1.0:初始 POC(概念验证)。