CAB(Composite UI Application Block)学习记录
CAB话说和MVC及MVP差不多但本人看了三天仍然是一头雾水!
下面把相关资料放上,以共同学习,提前声明如果有侵权请通知我立刻删除!谢谢!
RootWorkItem.UIExtensionSites.RegisterSite
这个方法设计有什么用?
主要是为了便于子模块插入和更新一些菜单,工具按钮之类的东西
Site
即是菜单,工具按钮之类的场所,你可以注册多个
site,
如
MainMenu,
标准工具条
Standard,
状态条
StatusBar
,例子
RootWorkItem.UIExtendsionSites.RegisterSite("MainMenu",Shell.MainMenuStrip);
RootWorkItem.UIExtendsionSites.RegisterSite("Standard",Shell.ToolBar);
RootWorkItem.UIExtendsionSites.RegisterSite("StatusBar",Shell.StatusBar);
默认的,在
form
中的控件都是私有的。
ToolBar,StautsBar
均需要改变
private,
到
public(internal)
(需要测试
)
MainMenuStrip
显然是
.net 2.0
设置的快捷访问方式,如同
.net 1.1
中的
Menu,
如果你在
form
上放置了一个
MenuStrip
,
mainMenuStrip
属性就反映了这个
MenuStrip
一旦注册了
site,
你可以在任意
workitem
中添加自定义的菜单或工具按钮,并进行映射
在我惯用的写法中,
toolbar,menubar
往往为所有模块所共用,当点击一个
save
按钮或菜单时,不同模块的执行动作是不同的,在我早先的插件架构中,
IWindowPlugin
有个
AfterComamndClick
方法,传入点击的
command name,
不同模块实现各自的执行方法
cab
的
command
显然是另一条路,首先,你编写该模块的各种方法,如
save,delete,refresh
之类的,然后用
CommandHandler
标记为
command,
最后进行映射
映射实际上就是,某一菜单或工具按钮该执哪个
workitem
的那个
command
代码
如果要一个容器成为一个
UIExtensionSite
,其则要为其实现
IUIElementAdapter
接口,并实现
IUIElementAdapterFactory
,目前,
cab
仅支持
ToolStrip,ToolStripItem
及其实现类,这就意味这,像
StatusStrip,MenuStrip,ToolStrip
等均可以注册到
UIExtendSite
集合中,而像
Panel
之类的,显然不行,不过实现起来倒也不是很难,
CompositeUI.WinForms.UIElements
一个好的参考
由于
IUIElementAdapter
只提供
add,remove
方法,包括
UIExtensionSite
也是,缺少从已存在
site
中取出对象的功能,如果要操作层次型菜单,目前应该是个不太可能的任务,如在主菜单的
file
菜单中增加
filenew
菜单,折衷的办法是将
file
注册为
UIExtensionSite
在我设想的应用程序类型中,各个子窗口,一般的,像用
tab
表示的共享一个菜单和工具条,但
cab
的
command
显然不适合这种模式。因为在这种模式下,通常有个当前文档的概念,菜单和工具条仅对当前文档有效。在
cab
的
command
模式中,所有注册了
CommandHandler
的过程均会响应,显然,这不是我们希望的。当然,如果像一个保存全部,这样
,command
还是很有用的
|
cab
显然有太多的概念了,就像我这样的老手
:)
,也难在一天内把握其思路,让我们看看有没有快速使用它的捷径。
第一步
①
创建一个从
FormShellApplication
继承的类
②
创建一个
Root Workitem
public class CABDemoApplication : FormShellApplication<CABDemoWorkItem,Form1>
{
{
[STAThread()]
public static void Main()
{
CABDemoApplication app = new CABDemoApplication();
app.Run();
}
}
public static void Main()
{
CABDemoApplication app = new CABDemoApplication();
app.Run();
}
}
public class CABDemoWorkItem : WorkItem
{
}
{
}
就像这样
第二步
先扔掉
mvc
的概念,改变一下习惯,在以前,我们要创建一个入库输入界面,首先是创建一个
form
,现在,我们是创建一个
user control
,并用
SmartPart attribute
标记这个控件。
[SmartPart]
public partial class InStockInput : UserControl
{
public InStockInput()
{
InitializeComponent();
}
}
public partial class InStockInput : UserControl
{
public InStockInput()
{
InitializeComponent();
}
}
在这个控件中实现所有逻辑
第三步
最后就是显示这个
control
,这个任务的代码都是类似的
首先,我们需要将这个
control
加入到
workitem
的
SmartPart
集合
其次,我们在一个指定的
workspaces
中显示它
请大家注意加粗的两行代码,通常,我们选择在
OnRunStarted
中将视图加入到集合中
但是,显示的通常不一定是在这个过程中,它可以在点击菜单或是点击某个特定的树状导航节点时进行
public class CABDemoWorkItem : WorkItem
{
protected override void OnRunStarted()
{
base.OnRunStarted();
{
protected override void OnRunStarted()
{
base.OnRunStarted();
InStockQueryView csp = this.SmartParts.AddNew<InStockQueryView>();
Workspaces["InStockQueryWorkspace"].Show(csp);
}
Workspaces["InStockQueryWorkspace"].Show(csp);
}
}
第四步
-
概念进阶
SmartPart
和
SmartPartInfo
这点其实很好理解,就是
smartpart
和描述分离,我的插件框架中就有
plugin
和
plugindescriptor,smartpart
和
smartpartinfo
也是一个理
像
TabSmartPartInfo
就提供了这个
smartpart
显示在
tabworkspace
中的一些
descriptor,
如
tab
上的文本是什么,显示的时侯是否设置这个
smartpart
为活动的,显示在最后还是最前等。
一个
smartpart
可以有多个
smartpartinfo,
这样,当其显示在不同的
workspace
中,可以呈现不同的外观
,
待验证
mvc
model-view-controller
这里
model
是数据,他可以是一个
dataset,datatable
或是一个
entity
类,如
Customer,Area,model
被
view,controller
共用(即这两者均会用到
)
view-
在这里
,view
特指标注上
SmartPart attribute
的
usercontrol
,
view
向
controller
请求数据并显示数据,标准的
mvc
设计中,
view
总是需要依赖一个或多个
controller
为了减少这个依赖,为
controller
抽象一个接口是一个好的想法,让
view
依赖
controller
的接口而不是具体的
controller
类,当然,这在
quick and dirty
的设计环境中,并不需要这样。
controller —
这里,
controller
是指继承
Controller
类的一个普通的
.net
对象,它从
view
中获得参数,处理后返回数据给
view
mvc
和
services
严格的设计中,
controller
不处理业务逻辑,业务逻辑将转发到
services
层去进行,这里为了减少
controller
对
services
的依赖,通常也为
services
抽象接口
WorkItem
和
MVC
WorkItem
在
mvc
之上,它是一个
module
的启动点,如
InStockWorkItem.Run,
在
workitem
中,通常的任务就是作初始化和显示
view
一个
workitem
,按文档中说是一个
usecase
,显然它是从宏观上来看应用程序布局,在
mvc
中,
controller,view
等都在做更细致的工作
Module
小的项目,可以将所有实现在一个项目中完成,必要时可以使用文件夹和命名空间进行分离。
cab
本质上是一个插件应用程序。各人可以做自己的项目,然后再合并,为了让
cab
定位这些项目
,cab
中引入了
module
的概念
①
一个
Module
是一个
class library
或是
user control
项目
②
assemblyinfo.cs
中有一下
attribue
标识
[assembly: Microsoft.Practices.CompositeUI.Module("mainMod")]
mainMod
是模块名,在设置模块依赖时有用
③
一个
module
可能依赖其它模块,这时需要使用
ModuleDependency attribute
[assembly: Microsoft.Practices.CompositeUI.ModuleDependency(
"TheModuleYouDependOn")]
④
模块初始化
·
创建一个从
ModuleInit
继承的类
·
如果需要程序化加载服务
,
覆盖
AddService
方法
·
如果需要显示用户接口或是定制逻辑,覆盖
Load
方法
⑤
最后一步,就是便是
ProfileCatalog.xml
,这个文件同
app.config
在同一个位置,使应用
load
这些模块
<?xml version="1.0" encoding="utf-8" ?>
<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile">
<Modules>
<ModuleInfo AssemblyFile="Mod1.dll"/>
<ModuleInfo AssemblyFile="Mod2.dll"/>
</Modules>
</SolutionProfile>
过度设计
通常,你需要明确以上的思路,这是你重构应用的准则,但在实际中,你并不需要像这样做,我个人而言,是否做严格的分离完全取决于你是否能够掌控代码,如果代码的规模在你能把握的范围内,全部的东西都在
view
端也是可以的,怎么顺手怎么来