65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WPF Calendar 中高亮显示日期

starIconstarIconstarIconstarIconstarIcon

5.00/5 (9投票s)

2013年2月18日

CPOL

2分钟阅读

viewsIcon

41904

downloadIcon

2420

在 WPF Calendar 中高亮和标记单个日期

介绍 

我希望使用 WPF 日历并突出显示和标记感兴趣的单个日期。我在网上搜索,但找不到任何可用的解决方案。我找到了微软的“RedLetterDays”:http://msdn.microsoft.com/en-us/magazine/dd882520.aspx#id0430067,但它只能与 WPF Toolkit 一起工作,而且可配置性不高。这个解决方案不依赖于修改日历,而是修改背景。

使用代码 

使用这段代码非常简单,分为四个步骤:

  1. 设置日历
  2. 设置图标
  3. 设置日期
  4. 更改日期时更新背景

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(概念验证)。
© . All rights reserved.