EuropeanCastle.Books 类库现在有两本书,而后我添加了第三本书 CSharpProfessionProgrammingBook 类C# 高级编程,但他是空的,还没有准备编写他,现在仔细查看 EuropeanCastle.Books 类库的所有类,除了 Catalogue 类,都有一些相似的方法和接口,创建并继承 BindingableBase 基类,所有书都有目录属性,章节和节都有名称属性,理应给他们继承一个 BookBase 基类,他们都有相似的行为,同时他们又是可以绑定的,又可以继承 BindingableBase 基类
public class BindingableBase : INotifyPropertyChanged
{
protected BindingableBase()
{
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
var propertyChanded = PropertyChanged;
if (propertyChanded != null)
{
PropertyChanged(this, e);
}
}
protected void SetProperty<T>(ref T item, T value, [CallerMemberName]string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(item, value))
{
item = value;
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
创建 BookBase 基类时,成员 Catalogue 属性现在有一个问题,是使用 Catalogue 类型,还是LinkedList< Section > 类型,
这是因为,
FrameworkDesignGuidelinesBook 类的 Catalogue 属性使用 Catalogue 类型,
WpfProgrammingValuables2012Book 类的 Catalogue 属性使用 LinkedList< Section > 类型,
如果让他们继承 BookBase 基类,必须统一使用同一类型,然而,可以再添加属性 Catalogue2 ,带数字后缀的属性不到非不得已,最好不要使用,这样非常不直观,应当让他们使用一致的结构模型,这里面临择决,自定义类型可以有更多控制机会,使用 LinkedList< Section > 类型,就必定是链表结构了,当在 WPF 桌面程序使用绑定时,他会连子结点一起显示为同一层,这不是希望的。
下面是修改为 WpfProgrammingValuables2012Book 书的结果,他没有分层,把子层都放到同一层了
上面的图的目录是错误的,最开始我理解链表产生的错误,编码时就不自觉的以为是分层结构,他是将多条线段连成不断的线段结构,现在修正这个错误。注意,先前的代码是错误的,导致目录信息错误
尽管修正了错误,在使用链表时,他不是分层数据结构,而是头尾相连的对象,看起来像是有层次感的,他是一条不间断的线段结构,除了根结点,但非常遗憾的是,树控件不使用这种结构,他只是普通的集合控件,里面每项可以再包含自己的集合,所以造成上次理解错误
所以现在,链表这种数据结构不适用我所希望的结构,他无非就有一个好处,插入删除某一结点的数据很快,对于当前应用程序,这不是需要的结构,所以,这种方案否决了,如果非要使用这种结构,又要在绑定 WPF 程序时绑定到树控件时,以树的形式展示出来,这需要重写迭代器,然而,这是不可能的,迭代器不能重写,只有在自定类中实现链表功能,并使用自己的迭代器,迭代链表的首层结点,其他结点跳过,然而,这还不如使用自义类来得方便
还有一个问题,使用 Chapter 类表示章,使用 Section 类表示节,章和节的类,属性成员出奇的相似,这可以并为一个类,简化操作,但是,如果你想让章和节表示不同的对象,哪怕他们的成员相似,仍然有理由使用两个类分别表示这两种对象,以便添加不同的成员,甚至给他们编写基类,但是现在还不需要他,所以没必要再多写一个基类出来,但不久的将来,随的程序的复杂,很快他们就需要一个基类 。现在让 Chapter 类, Section 类继承 BindingableBase 基类, 删除基类实现的代码
public class Section : BindingableBase, IEnumerable<Section>
{
...
public event PropertyChangedEventHandler PropertyChanged;//删除
protected void OnPropertyChanged(PropertyChangedEventArgs e){...}//删除
protected void SetProperty<T>(ref T item, T value,
[CallerMemberName]string propertyName = null){...}//删除
...
}
public class Chapter : BindingableBase
{
...
public event PropertyChangedEventHandler PropertyChanged;//删除
protected void OnPropertyChanged(PropertyChangedEventArgs e){...}//删除
protected void SetProperty<T>(ref T item, T value,
[CallerMemberName]string propertyName = null){...}//删除
...
}
还需要调整一下细节,Section 类删除迭代器接口和实现方法,修改 Catalogue 类,改调用 Section 类的 Sections 属性,因为还不想让 Section 类实现迭代,他的成员 Sections 属性才是要使用的
public class Catalogue : ObservableCollection<Chapter>
{
...
public IEnumerable<string> GetEnumeratorTreeView()
{
...
foreach (var nestSection in section.Sections)//改调用他的属性
{...}
...
}
...
}
给 BookBase 基类继承 BindingableBase 基类,添加 Catalogue 属性,添加一个 Name 属性,表示书名,所有书类继承 BookBase 基类,删除基类实现代码,在构造函数给书名赋值,修正初始化目录信息的数据,并让ToString() 方法返回 Name 属性
public class BookBase : BindingableBase
{
private string name;
private Catalogue catalogue = new Catalogue();
protected void BookBase()
{
}
public string Name
{
get { return name; }
set { SetProperty(ref name, value); }
}
public Catalogue Catalogue
{
get { return catalogue; }
set { SetProperty(ref catalogue, value); }
}
}
由于初始化一本书的目录代码比较多,可以给每一章添加私有方法,并在构造函数中调用他
public class FrameworkDesignGuidelinesBook : BookBase
{
public FrameworkDesignGuidelinesBook()
{
Name = ".NET 设计规范约定、惯用法与模式(第二版)";
InitCatalogue();
}
public override string ToString()
{
return Name;
}
private void InitCatalogue()
{
Catalogue.Add(InitCatalogueOne())
...添加其他初始化信息...
}
private Chapter InitCatalogueOne()
{
return new Chapter("概述",
new ObservableCollection<Section>
{
new Section("精心设计的框架所具备的品质", 2,
new ObservableCollection<Section>
{
new Section("精心设计的框架所具备的品质",2),
new Section("精心设计的框架是简单的",2),
new Section("精心设计的框架代价高",3),
new Section("精心设计的框架充满利弊权衡",4),
new Section("精心设计的框架应该借鉴过去的经验",4),
new Section("精心设计的框架要考虑未来的发展",5),
new Section("精心设计的框架应具有良好的集成性",5),
new Section("精心设计的框架是一致的",7,
new ObservableCollection<Section>
{
new Section("假设有第四层",-1),
}),
})
});
}
private Chapter InitCatalogueTwo()
{...}
...其他成员...
}
如果你不想让太多的私有方法污染 FrameworkDesignGuidelinesBook 类,
可以在类库创建内部类 FrameworkDesignGuidelinesBookInitCatalogue 类,方法 NewChapterOne(),NewChapterTwo(),NewChapterThree(),…以此类推,并在 FrameworkDesignGuidelinesBook 类调用,也可以创建工厂类,但这里只是内部使用,不必使用工厂类
可以在 Visual Studio 2012 代码编辑器中,使用左右双页来编写代码,这样更方便重构代码
注意, 在代码编辑器中,使用了 Consolas 字体,而不是默认的新宋体