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

创建 Outlook 日历(使用 WPF,第一部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (70投票s)

2008 年 10 月 22 日

CPOL

2分钟阅读

viewsIcon

287866

downloadIcon

13933

使用WPF重新创建Outlook日历。

引言

微软Office无疑是当今世界上最畅销的产品之一!他们总是在尝试创新…… 在这篇CodeProject文章中,我将尝试使用WPF重新创建Microsoft Outlook日历控件。

WPF中的所有元素/控件都是无外观的! 这减少了创建自定义控件的需求。 按钮是一个支持点击并触发Click事件的元素,但是对按钮的外观**没有**限制!

因此,在我的WPF思考帽的帮助下,我试图找到一个我可以重新设置样式的控件以适应我的日历控件……在尝试了一些想法之后,我决定创建自定义控件。

以下是我的自定义Calendar控件的基本元素

CalendarLedgerItem和CalendarLedger

Ledger.jpg

分类帐指示时间槽时间。

CalendarTimeslotItem

Timeslot.jpg

每一天被分成30分钟的时隙(由CalendarTimeslotItem表示)。 CalendarTimeslotItem提供了一个非常简单的悬停样式,以提示用户,通过点击时隙,您可以添加一个预约。 CalendarTimeslotItem还公开(并引发)AddAppointmentEvent,该事件被冒泡到日历(通过点击时隙)。 CalendarTimeslotItem派生自ButtonBase

public static readonly RoutedEvent AddAppointmentEvent = 
    EventManager.RegisterRoutedEvent("AddAppointment", RoutingStrategy.Bubble, 
    typeof(RoutedEventHandler), typeof(CalendarTimeslotItem));

CalendarAppointmentItem

AppointmentItem.jpg

CalendarAppointmentItem是一个非常通用的容器,用于显示预约(类似于ListboxItem)。 我有点作弊,假设绑定到CalendarDay的每个“item”都将具有StartTimeEndTime属性!

<Setter Property="StartTime" Value="{Binding StartTime}" />
<Setter Property="EndTime" Value="{Binding EndTime}" />

[注意] 我知道这有点糟糕…… 我将在第2部分中解决这个问题!

CalendarDay

CalendarDay是我们Outlook日历的核心。 CalendarDay派生自ItemsControl

protected override DependencyObject GetContainerForItemOverride()
{            
    return new CalendarAppointmentItem();
}

protected override bool IsItemItsOwnContainerOverride(object item)
{
    return (item is CalendarAppointmentItem);
}

添加到CalendarDay的每个“item”都将隐式地将其CalendarAppointmentItem作为其容器。 只要绑定到ItemsControl的对象具有StartTimeEndTime属性,这一切都将“神奇地”工作!

TimeslotPanel

在查看日历控件之前,我们需要介绍的最后一部分是TimeslotPanel。 这个自定义布局面板将根据其开始时间和结束时间在CalendarDay控件中定位每个“item”!

<ItemsPanelTemplate>
    <local:TimeslotPanel />
</ItemsPanelTemplate>

日历

CalendarCalendarTimeslotItem.AddAppointmentEvent添加了一个所有者。

public static readonly RoutedEvent AddAppointmentEvent = 
    CalendarTimeslotItem.AddAppointmentEvent.AddOwner(typeof(CalendarDay));

目前,Calendar控件是唯一明确“知道”日期是什么的控件! 它有一个CurrentDate属性。

public static readonly DependencyProperty CurrentDateProperty =
    DependencyProperty.Register("CurrentDate", typeof(DateTime), typeof(Calendar),
        new FrameworkPropertyMetadata((DateTime)DateTime.Now,
            new PropertyChangedCallback(OnCurrentDateChanged)));

Calendar控件还公开了两个可用于更改当前日期的命令

public static readonly RoutedCommand NextDay = 
       new RoutedCommand("NextDay", typeof(Calendar));
public static readonly RoutedCommand PreviousDay = 
       new RoutedCommand("PreviousDay", typeof(Calendar));

Commands.jpg

这些命令是不言自明的!

我还创建了一个非常基本的模型

Model.jpg

此模型用作数据源!

public static readonly DependencyProperty AppointmentsProperty =
    DependencyProperty.Register("Appointments", 
       typeof(IEnumerable<Appointment>), typeof(Calendar),
    new FrameworkPropertyMetadata(null, 
        new PropertyChangedCallback(Calendar.OnAppointmentsChanged)));

现在,唯一棘手的部分是如何将数据绑定到我的Appointments属性到我的ItemsControl中?

引入过滤器…… Rob Conery 的 MVC Storefront 使用了类似的方法!

public static class Filters 
{ 
    public static IEnumerable<Appointment> ByDate(
           thisIEnumerable<Appointment> appointments, DateTime date) 
    { 
        var app = froma inappointments 
                  wherea.StartTime.Date == date.Date 
                  selecta; 
        return app; 
    } 
}

这个扩展方法允许我按日期“过滤”我的预约(忽略时间)。 这是目前的使用方式

private void FilterAppointments()
{
    DateTime byDate = CurrentDate;
    CalendarDay day = this.GetTemplateChild("day") as CalendarDay;
    day.ItemsSource = Appointments.ByDate(byDate);

    TextBlock dayHeader = this.GetTemplateChild("dayHeader") as TextBlock;
    dayHeader.Text = byDate.DayOfWeek.ToString();
}

这种方法允许我相对容易地扩展日历控件以支持日视图或周视图(只需添加多个CalendarDay控件)。

OutlookCalendar.jpg

好了,这就是第1部分的内容... 如果您觉得这篇文章有趣,请为它投票,并访问我的博客

© . All rights reserved.