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






4.55/5 (19投票s)
使用 WPF 创建 Outlook 日历(和约会)系列文章的第二部分。
一生都在犯错,不仅更光荣,而且比一生无所事事更有用。
- 乔治·萧伯纳
引言
在 第一部分 之后,我决定真正专注于如何使 Calendar
控件更好、更“专业”。 假设我想出售这个控件。 如果我购买控件,我希望有像样的设计时支持,并且我希望控件可定制样式。 我的第一次尝试失败了!!! 让我们尝试改进它……
项生成
在以前版本的 Calendar
中,所有的 CalendarLedgerItem
和 CalendarTimeslotItem
都是手动创建的! 这是绝对不行的……
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()
)。
样式,样式,样式
Calendar
目前暴露了 CalendarLedgerItem
、CalendarTimeslotItem
和 CalendarAppointmentItem
的样式。
所有的样式都暴露为 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); }
}
现在剩下要做的就是将 CalendarLedgerItem
、CalendarTimeslotItem
和 CalendarAppointmentItem
的 StyleProperty
绑定到这些 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 设计时支持目前是一个热门话题!
<>
Calendar
控件实际上由一些基本元素组成,例如 CalendarLedger
、CalendarDay
等。 我不希望这些基本元素出现在我的工具箱中! 我只希望我的 Calendar
控件是“可选的”。
要从工具箱中删除控件,请添加以下属性
[ToolboxBrowsable(false)]
还要注意我现在拥有的“酷”自定义图标! 这是通过添加具有特定名称(Calendar.Icon.bmp)的嵌入式资源来实现的。 也可以使用 ThumbnailAttribute
指定图标!
在 Expression Blend 中,属性网格被分为几个类别!
[Category("Calendar")]
每个类别也被细分为“普通”部分和一个包含一些“高级”属性的扩展器。
要将属性放置在“高级”扩展器中
[EditorBrowsable(EditorBrowsableState.Advanced)]
或者将其放置在“普通”部分中
[EditorBrowsable(EditorBrowsableState.Always)]
命名部件
设计可重用控件的常见做法是使用命名部件! 在我的 Calendar
控件中,我需要访问 CalendarDay
控件。 要访问此控件,我首先给它一个名称
<calendarledger x:name="PART_Ledger" />
下一步是重写 Calendar
的 OnApplyTemplate
CalendarDay _day;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_day = GetTemplateChild(ElementDay) as CalendarDay;
if (_day != null)
{
_day.Owner = this;
}
}
在 OnApplyTemplate
中,我尝试定位命名部件(通过使用 GetTemplateChild()
)。
现在,我可以完全访问 CalendarDay
控件!!! 唯一需要注意的另一件事是我还设置了我的 CalendarDay
的 Owner
。 这允许我的 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))]
此属性使确定命名部件应该是什么类型变得容易!
摘要
第二部分到此结束!!!
历史
- 2008 年 11 月 11 日:初始发布。