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

创建 Outlook 日历(WPF 版)(第 2 部分)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (19投票s)

2008年11月12日

CPOL

2分钟阅读

viewsIcon

121782

downloadIcon

7291

使用 WPF 创建 Outlook 日历(和约会)系列文章的第二部分。

一生都在犯错,不仅更光荣,而且比一生无所事事更有用。

- 乔治·萧伯纳

引言

第一部分 之后,我决定真正专注于如何使 Calendar 控件更好、更“专业”。 假设我想出售这个控件。 如果我购买控件,我希望有像样的设计时支持,并且我希望控件可定制样式。 我的第一次尝试失败了!!! 让我们尝试改进它……

项生成

在以前版本的 Calendar 中,所有的 CalendarLedgerItemCalendarTimeslotItem 都是手动创建的! 这是绝对不行的……

CalendarLedger 负责创建所有的 CalendarLedgerItem。 调用 PopulateLedger() 将动态创建所有的账本项目!

private void PopulateLedger()
{
    if (_ledgerItems != null)
    {
        for (int i = 0; i < 24; i++)
        {
            CalendarLedgerItem item = new CalendarLedgerItem();
            item.TimeslotA = i.ToString();
            item.TimeslotB = "00";
            item.SetBinding(CalendarLedgerItem.StyleProperty, 
            GetOwnerBinding("CalendarLedgerItemStyle"));
            _ledgerItems.Children.Add(item);
        }
    }
}

CalendarDay 也负责创建 CalendarTimeslotItems(通过调用 PopulateDay())。

样式,样式,样式

CalendarProperties.jpg

Calendar 目前暴露了 CalendarLedgerItemCalendarTimeslotItemCalendarAppointmentItem 的样式。

所有的样式都暴露为 DependencyProperty

public static readonly DependencyProperty CalendarTimeslotItemStyleProperty =
    DependencyProperty.Register("CalendarTimeslotItemStyle", 
                typeof(Style), typeof(Calendar));

public Style CalendarTimeslotItemStyle
{
    get { return (Style)GetValue(CalendarTimeslotItemStyleProperty); }
    set { SetValue(CalendarTimeslotItemStyleProperty, value); }
}

现在剩下要做的就是将 CalendarLedgerItemCalendarTimeslotItemCalendarAppointmentItemStyleProperty 绑定到这些 DependencyProperty

timeslot.SetBinding(CalendarTimeslotItem.StyleProperty, 
        GetOwnerBinding("CalendarTimeslotItemStyle"));

命名空间

通过添加以下属性...

[assembly: XmlnsDefinition(http://schemas.rudigrobler.com/wpf/2008, 
    "RudiGrobler.Controls")]

... 现在可以很容易地引用我的控件,而无需记住所有的命名空间。

xmlns:rg=”http://schemas.rudigrobler.com/wpf/2008” 

设计时支持

Visual Studio 和 Expression Blend 设计时支持目前是一个热门话题!

<>CalendarInToolbox.jpg

Calendar 控件实际上由一些基本元素组成,例如 CalendarLedgerCalendarDay 等。 我不希望这些基本元素出现在我的工具箱中! 我只希望我的 Calendar 控件是“可选的”。

要从工具箱中删除控件,请添加以下属性

[ToolboxBrowsable(false)]

还要注意我现在拥有的“酷”自定义图标! 这是通过添加具有特定名称(Calendar.Icon.bmp)的嵌入式资源来实现的。 也可以使用 ThumbnailAttribute 指定图标!

CalendarIcon.jpg

在 Expression Blend 中,属性网格被分为几个类别!

[Category("Calendar")] 

CalendarProperties.jpg

每个类别也被细分为“普通”部分和一个包含一些“高级”属性的扩展器。

要将属性放置在“高级”扩展器中

[EditorBrowsable(EditorBrowsableState.Advanced)]

或者将其放置在“普通”部分中

[EditorBrowsable(EditorBrowsableState.Always)]

命名部件

设计可重用控件的常见做法是使用命名部件! 在我的 Calendar 控件中,我需要访问 CalendarDay 控件。 要访问此控件,我首先给它一个名称

<calendarledger x:name="PART_Ledger" />

下一步是重写 CalendarOnApplyTemplate

CalendarDay _day;
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    _day = GetTemplateChild(ElementDay) as CalendarDay;
    if (_day != null)
    {
        _day.Owner = this;
    }
}

OnApplyTemplate 中,我尝试定位命名部件(通过使用 GetTemplateChild())。

现在,我可以完全访问 CalendarDay 控件!!! 唯一需要注意的另一件事是我还设置了我的 CalendarDayOwner。 这允许我的 Calendar 天在其 Owner 上设置绑定

public Calendar Owner { get; set; }

private BindingBase GetOwnerBinding(string propertyName)
{
    Binding result = new Binding(propertyName);
    result.Source = this.Owner;
    return result;
}

使用命名部件的最佳实践始终是以 PART_ 开头命名,并向控件添加以下属性

[TemplatePart(Name = CalendarLedger.ElementLedgerItems, Type = typeof(StackPanel))]

此属性使确定命名部件应该是什么类型变得容易!

摘要

第二部分到此结束!!!

- Rudi Grobler

历史

  • 2008 年 11 月 11 日:初始发布。
使用 WPF 创建 Outlook 日历(第二部分)- CodeProject - 代码之家
© . All rights reserved.