上篇文章我向大家介绍了BlogEngine.Net中开发扩展的重要一部分——Extension。在本文中我将向大家展示它的另外一种扩展特性,那就是Widget小工具,主要是Widget的开发标准和工作原理等。
什么是Widget与为什么要使用Widget
Widget实际上就是一种带有界面的小工具,主要应用在桌面领域,例如:Yahoo!Widget,还有Vista自带的边栏等。在BlogEngine.Net中它就是页面左侧或右侧的那种小的分区,例如Category list,Calendar,Tag cloud等,这种东西实际上在很多Blog系统中都存在,在BlogEngine.Net中我们就叫它Widget。
Widget可以将Blog系统中很多的功能提供给用户一个统一的界面访问接口。如果有一些功能需要加到页面上,我们首先考虑的就是可否作成一个Widget来实现,因为这种Widget具有统一的开发标准,可以很方便的达到我们的目的。
WidgetBase和WidgetEditBase
在BlogEngine.Net中,作为一个有界面的Widget我们只需要继承WidgetBase类就行了。WidgetBase直接继承了UserControl,重写了Render用来生成统一的Widget界面,至于具体Widget中显示什么,则由自定义Widget类本身来完成,WidgetBase中有一个抽象方法LoadWidget用来完成Widget对象的初始化工作,IsEditable用于说明Widget是否可以编辑,如果可以编辑在Render时就会输出编辑按钮,那么这个Widget也必须提供一个编辑界面(继承了WidgetEditBase)。此外还需要注意WidgetBase中GetSettings会根据WidgetID从DataStore(前文讲述过)中获得相应的配置信息(也就是内容信息)并存储在Cache中。Cache在这部分的DataStore的处理中运用很多,希望大家留意。
如果某个Widget可以编辑,那么它还需要一个实现WidgetEditBase的类,这个类主要是给用户提供一个对于Widget配置信息(具体内容)修改的界面,它提供了一个抽象的Save方法用于将修改的信息保存到DataStore中,还有一个Saved事件用于外部监听以便进行扩展。
所有已经实现的Widget必须放在widgets目录下,并以Widget的名称给相应的文件夹命名,如果只是浏览我们加入一个widget.ascx就行了,如果需要修改还需要加入一个edit.ascx,以TextBox(可以设置一些关于作者的描述信息)的实现为例:
在widgets\TextBox中有widget.ascx和edit.ascx两个文件(加上Codebehind一共四个),在widget.ascx.cs的LoadWidget(重写父类的方法)获得DataStore信息并加入到Widget内容中。
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
15
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
20
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
21
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
24
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
32
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
33
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
同样对于edit.ascx.cs中重写了父类的Save方法将内容又保存回DataStore中。
Widget的增,删,改,排序等是如何处理的
在admin目录下存在WidgetEditor.aspx用来对Widget的操作进行处理。它实际上是一个通用的模板,也是一个操作的路由,根据请求的参数进行相应的操作。
增加Widget:我们将自己的按照上文的标准开发的Widget放在widgets的目录以后就已经完成了Widget的安装。通过添加列表(这是WidgetZone生成的一个列表,实际上就是搜索widgets目录下的文件而获得的所有已安装的Widget列表)就可以转向WidgetEditor.aspx,之后将这个Widget添加进来,而WidgetEditor.aspx是通过AddWidget方法完成的。
删除Widget:这里的删除不是卸载,而只是从WidgetZone中移出Widget,同时删除DataStore信息。当我们点击Widget中的删除时会使用WidgetEditor.aspx来处理,而WidgetEditor.aspx又是通过RemoveWidget完成的。
修改Widget:当我们点击Widget的修改时会转向WidgetEditor.aspx,而WidgetEditor.aspx使用InitEditor读取了DataStore中的信息并加载了相应Widget中的edit.ascx,实际上对于Widget的修改一部分(总体的描述信息)是通过WidgetEditor.aspx直接修改完成的,而另一部分(Widget的配置信息)则是由WidgetEditor.aspx委托edit.ascx来完成的,这样做的好处显而易见,可以实现修改界面的个性化处理,这也是继承带来的好处。
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
排序Widget:当我们在拖动某个Widget时它会进行新的排序,这个排序是持久性的。最初见到BlogEngine.Net时这个功能就很吸引我。那么它是如何实现的呢?
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
1
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
从这里可以看出move是一个使用";"分隔的WidgetID序列来表示顺序,这个序列是JavaScript生成的。服务器接收到这个序列以后使用MoveWidgets并对于DataStore中的Widget列表进行重新的排序。对于JavaScript的实现已经超出本文的范围,这里不做讨论。感兴趣的朋友可以研究一下admin/widget.js,Widget这部分的所有JavaScript都在此,写的也是不错的。
由此可见WidgetEditor.aspx是Widget管理的一个核心。
WidgetZone是一个Widget的容器
WidgetZone上文已经涉及到,它就是一个Widget的容器。WidgetZone继承自PlaceHolder,在OnLoad时会根据DataStore将已经添加的Widget加载到PlaceHolder中,在Render的时候还会去查找安装在widgets目录下的Widget列表。这个WidgetZone在BlogEngine.Net中并不是一个必须的类,你可以将Widget直接放在主界面的某个位置上就可以使用。但是,如果不使用它来管理而直接显示Widget会失去Widget的管理特性,在下一篇制作Theme的文章中我会对其进行详细的说明。
总结
Widget的实现无非是BlogEngine.Net中的经典。BlogEngine.Net对这些界面上的小工具进行了统一的抽象,尤其是继承的使用带来了很大的扩展空间。WidgetEditor.aspx的统一管理也是非常经典的,尤其是排序和修改部分更值得大家仔细研究。此外,Widget的XCopy安装也是很不错的,实际上BlogEngine.Net的一个重要特性就是在Web上实现了很多这种热插拔(Plug'n play),包括Extension,Widget等。
继承的正确使用给我们带来的好处实在太多
上一篇:BlogEngine.Net架构与源代码分析系列part9:开发扩展(上)——Extension与管理上的实现
下一篇:BlogEngine.Net架构与源代码分析系列part11:开发扩展(下)——自定义Theme
【来源】: http://thriving-country.cnblogs.com/
本文版权归作者和博客园共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。