前一节中介绍了ViewPort,APPMenuTree定位在west region,继承自Ext.tree.Panel,需要实现的功能是从数据库System_Purview表中获取menu数据生成tree,并实现tree node的单击,在MainPanel中动态加载Tab。关键在于如何生成tree所需的Json数据,而tree的Json数据格式是这样的:
[
{id:'01',text:'01',children:[
{id:'01-01',text:'01-01',leaf:true},
{id:'01-02',text:'01-02',children:[
{id:'01-02-01',text:'01-02-01',leaf:true},
{id:'01-02-02',text:'01-02-02',leaf:true}
]},
{id:'01-03',text:'01-03',leaf:true}
]},
{id:'02',text:'02',leaf:true}
]
首先tree我分为三级,root为静态构建,不用管它,第2级对应数据表的父级,第3级对应子级,这样我就定义了3个Model,System_Purview(Mindscape设计器自动生成),JSystem_Purview_Parent与JSystem_Purview_Child,来看一下代码。
System.csnamespace TESZ.Data.Model
{
public partial class JSystem_Purview_Child
{
public virtual string id { get; set; }
public virtual string text { get; set; }
public virtual bool expanded { get; set; }
public virtual bool leaf { get; set; }
}
public partial class JSystem_Purview_Parent
{
public virtual string id { get; set; }
public virtual string text { get; set; }
public virtual bool expanded { get; set; }
public virtual bool leaf { get; set; }
public IList<JSystem_Purview_Child> children { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NHibernateModelGenerator", "1.0.0.0")]
public partial class System_Purview
{
public virtual int PurviewId { get; set; }
public virtual int ParentPurviewId { get; set; }
public virtual string PurviewKey { get; set; }
public virtual string NavigationUrl { get; set; }
public virtual string ImageUrl { get; set; }
public virtual string PurviewName { get; set; }
static partial void CustomizeMappingDocument(System.Xml.Linq.XDocument mappingDocument);
public static System.Xml.Linq.XDocument MappingXml
{
get
{
var mappingDocument = System.Xml.Linq.XDocument.Parse(@"<?xml version='1.0' encoding='utf-8' ?>
<hibernate-mapping xmlns='urn:nhibernate-mapping-2.2'
assembly='" + typeof(System_Purview).Assembly.GetName().Name + @"'
namespace='TESZ.Data.Model'
>
<class name='System_Purview'
table='`System_Purview`'
>
<id name='PurviewId'
column='`PurviewId`'
>
<generator class='identity'>
</generator>
</id>
<property name='ParentPurviewId'
column='`ParentPurviewId`'
/>
<property name='PurviewKey'
column='`PurviewKey`'
/>
<property name='NavigationUrl'
column='`NavigationUrl`'
/>
<property name='ImageUrl'
column='`ImageUrl`'
/>
<property name='PurviewName'
column='`PurviewName`'
/>
</class>
</hibernate-mapping>");
CustomizeMappingDocument(mappingDocument);
return mappingDocument;
}
}
}
}
数据访问层ISystem_PurviewRepository,System_PurviewRepository就不列出来了,和第二节中的Location_Country同理,接着是Service:
ISystem_PurviewService.csnamespace TESZ.Services
{
public interface ISystem_PurviewService
{
IList<System_Purview> GetSystem_Purviews();
bool CreateSystem_Purview(System_Purview system_Purview);
IList<System_Purview> GetSystem_PurviewsParent();
IList<System_Purview> GetSystem_PurviewsChild(int parentPurviewId);
}
}
namespace TESZ.Services
{
public class System_PurviewService : ISystem_PurviewService
{
private TESZ.Data.DataAccess.ISystem_PurviewRepository _iSystem_PurviewRepository;
public System_PurviewService(TESZ.Data.DataAccess.ISystem_PurviewRepository iSystem_PurviewRepository)
{
_iSystem_PurviewRepository = iSystem_PurviewRepository;
}
public IList<TESZ.Data.Model.System_Purview> GetSystem_Purviews()
{
return _iSystem_PurviewRepository.FindAll();
}
public IList<TESZ.Data.Model.System_Purview> GetSystem_PurviewsParent()
{
return _iSystem_PurviewRepository.FindAll().Where(o => o.ParentPurviewId == 0).ToList();
}
public IList<TESZ.Data.Model.System_Purview> GetSystem_PurviewsChild(int parentPurviewId)
{
return _iSystem_PurviewRepository.FindAll().Where(o => o.ParentPurviewId == parentPurviewId).ToList();
}
public bool CreateSystem_Purview(TESZ.Data.Model.System_Purview system_Purview)
{
return _iSystem_PurviewRepository.Create(system_Purview);
}
}
}
然后就是Controller控制器提供Json数据了。
SystemPurviewController.cspublic partial class AppCenterController : Controller
{
//
// GET: /SystemPurview/
private IList<JSystem_Purview_Child> GetChildren(int parent)
{
var result = _iSystem_PurviewService.GetSystem_PurviewsChild(parent);
if (result != null && result.Count > 0)
{
var ts = from t in result.AsQueryable()
select new JSystem_Purview_Child()
{
id = t.PurviewKey.Trim(),
text = t.PurviewName.Trim(),
expanded = false,
leaf = true
};
return ts.ToList();
}
return null;
}
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult JGetParentPurviews()
{
var result = _iSystem_PurviewService.GetSystem_PurviewsParent();
var data = from t in result.AsQueryable()
select new JSystem_Purview_Parent()
{
id = t.PurviewKey.Trim(),
text = t.PurviewName.Trim(),
expanded = true,
leaf = false,
children = GetChildren(t.PurviewId)
};
return Json(data, JsonRequestBehavior.AllowGet);
}
}
最后是定义TreeStore,Tree以及Tree的单击事件。
ACMenuTreeStore.jsExt.define('Tesz.App.Stores.ACMenuTreeStore', {
extend: 'Ext.data.TreeStore',
alias: 'widget.acmenutreestore',
proxy: {
type: 'ajax',
url: 'JGetParentPurviews'
},
sorters: {
property: 'text',
direction: 'ASC'
}
});
ACMenuTreeStore继承自Ext.data.TreeStore,可以看出这里没有定义TreeStore的Model属性,因为只要获取符合TreeStore数据格式的Json字符串就可以了,而无需定义Fields。
AppMenuTree.jsExt.require('Tesz.App.Stores.ACMenuTreeStore');
Ext.define('Tesz.App.AppMenuTree', {
extend: 'Ext.tree.Panel',
alias: 'widget.appmenutree',
id: 'MAINMENU',
region: 'west',
autoScroll: true,
useArrows: true,
width: 220,
border: 0,
store: Ext.create('Tesz.App.Stores.ACMenuTreeStore'),
rootVisible: false,
root: {
id: 'root_node',
nodeType: 'async',
text: 'All Menus'
},
listeners: {
'itemclick': function (view, record) {
var leaf = record.get('leaf');
if (leaf) {
var id = record.get('id');
var text = record.get('text');
var tabPanel = Ext.getCmp('MAINPANEL');
var tab = tabPanel.getComponent(id);
if (!tab) {
tabPanel.add(Ext.create('Tesz.App.Panels.' + id)).show();
}
tabPanel.setActiveTab(tab);
}
else {
var expand = record.get('expanded')
if (expand) {
view.collapse(record);
}
else {
view.expand(record);
}
}
}
},
dockedItems: [{
xtype: 'toolbar',
items: [{
iconCls: 'x-expand-all',
tooltip: 'expand all nodes',
handler: function () {
Ext.getCmp('MAINMENU').expandAll();
}
}, {
iconCls: 'x-collapse-all',
tooltip: 'collapse all nodes',
handler: function () {
Ext.getCmp('MAINMENU').collapseAll();
}
}]
}]
});
AppMenuTree继承自Ext.tree.Panel,第1级node默认属性rootVisible: false设置为隐藏;通过Tree的"itemclick”事件来动态加载ACMainPanel的Tab,先判断node的"leaf”属性,如果为true则执行加载,如果为false则执行expand或collapse;所有的Tab的自定义组件都在Components/Panels文件夹,加载实现方法为tabPanel.add(Ext.create('Tesz.App.Panels.' + id)).show();如何来做到正确对应呢,可以参考事先定义的3个Model类,JSystem_Purview_Parent与JSystem_Purview_Child的"id”,也就是tree的nodeId,对应System_Purview表的PurviewKey字段,而所需加载的Tab,js组件文件名称与id都都定义为PurviewKey,这样就做到了一一对应;
CTRY.jsExt.define('Tesz.App.Panels.CTRY', {
alias: 'widget.ctry',
extend: 'Ext.Panel',
id: 'CTRY',
title: 'Country',
closable: true,
autoLoad: {
url: 'CountryPage',
scripts: true
},
listeners: {
resize: function () {
var main = Ext.getCmp('MAINPANEL');
var grid = Ext.getCmp('COUNTRYGRID');
if (grid)
grid.setWidth(main.getWidth()-5);
}
}
});
至此,主界面部分就基本完成了。费了好大的劲,研究调试好久才取得这样的结果,希望能和同僚们分享一下经验。