[译]用于将菜单项[Count]附加到菜单的灵活框架
By robot-v1.0
本文链接 https://www.kyfws.com/applications/flexible-framework-for-attaching-number-of-items-c-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 14 分钟阅读 - 6806 个词 阅读量 0[译]用于将菜单项[Count]附加到菜单的灵活框架
原文地址:https://www.codeproject.com/Articles/767753/Flexible-Framework-For-Attaching-Number-of-Items-C
原文作者:Asif
译文由本站 robot-v1.0 翻译
前言
Article will demonstrate how to develop generalize framework for creating Outlook style Auto Refresh Count of Menu Items
本文将演示如何开发通用框架以创建Outlook样式的自动刷新菜单项计数
介绍(Introduction)
在最近的开发活动中,我们遇到了一个RFC,我们的客户希望在过程中几乎实时地显示每个菜单项的计数.内部讨论导致形成某种框架,该框架应允许轻松快速地管理变更,即(While in recent development activity we have come across an RFC where our client wants to show counts against each menu item and in almost real time off course. Internal discussion leads to have some sort of framework that should allow managing change easy and quickly, that is)
- 将计数附加到新菜单应该不需要在所有应用程序层都进行更改(Attaching count to a new menu should not require changes at all application layers)
- 从菜单中删除计数完全不需要任何努力(Detaching a count from menu should not require any effort at all)
- 此区域的错误修复程序不需要完整版本(Bug fixes in this area should not require a complete release)
- 计数逻辑的更改应隔离进行,而无需修改任何现有层(Changes in the count logic should be done in isolation without modifying any existing layers) 我们已经搜寻了很多东西,但是找不到太多帮助,因此导致他们决定构建我们自己的框架,并通过撰写本文来帮助其他人,以防他们喜欢开发类似的功能.(We have googled and could not found much help which leads to a decision to build our own framework and help others by writing this article in case they like to develop similar feature.)
解(Solution)
基于上述要求,我们已经草拟了一个可以完成此工作的框架.伪解决方案可能是(Based on above requirements we have sketched a framework that will do the job. The pseudo solution could be)
- 应用程序应每隔n分钟向服务器请求AJAX调用(Application should request an AJAX call to the server every n minutes lets say)
- 服务器应返回某种XML,其中包含每个菜单项的数字(The server should return some sort of XML which contains numbers against each menu item)
- 应用程序通过迭代节点来处理xml.如果找到具有计数值的节点,它将更新树节点(Application process the xml by iterating the nodes. If it found a node that has count value it will update the tree node) 如果我们仔细研究以上方法,可以观察到该解决方案包含三层.让我们剖析每一层.(If we closely look at the above approach we can observe that solution has three layers. Lets dissect each layer.)
数据库层(Database Layer)
我们认为数据库应该掌握此框架的关键.作为标准业务应用程序菜单,大多数情况下是从存储每个用户权限的权限表中呈现的,登录后,用户权限将通过菜单动态加载并呈现.因此,我们看到了这种结构的明显变化,如果我们能够以某种方式将一些代码附加到每个权限/菜单上,我们的问题将得到解决.(We thought that database should hold the key to this framework. As standard business application menu mostly render from permission tables where each user’s permissions are stored and upon login the user’s permission loads and rendered via menu dynamically. So we see an obvious change in this structure, if somehow we could attach some code to each permission/menu our problem will get solved.)
假设我们具有存储权限的以下表结构(Let’s assume we have following table structure that store permissions)
功能编号(FunctionID) | FunctionParentID(FunctionParentID) | MenuDisplayText(MenuDisplayText) |
---|---|---|
1 | NULL | Area |
2 | 1 | Module |
3 | 2 | Functon |
|
在数据库层,运行的最精细的代码是函数.如果我们以某种方式在每个菜单上附加了一个功能,那么大多数问题都将得到解决. SQL函数是高度可维护的隔离的独立组件,因此我们决定使用函数.修改后的表结构如下所示:(At database layer the most granular code that runs is functions. If we somehow attach a function at each menu than our most of the problems gets solved. SQL Functions are isolated independent components that are highly maintainable so we have decided to use functions. The modified table structure would be like:)
功能编号(FunctionID) | FunctionParentID(FunctionParentID) | MenuDisplayText(MenuDisplayText) | CountFunction(CountFunction) |
---|---|---|---|
1 | NULL | Area | Dbo.get_GetAreaCount({0},{1},{2})(Dbo.get_GetAreaCount({0}, {1}, {2})) |
2 | 1 | Module | Dbo.get_GetModuleCount({0},{1},{2})(Dbo.get_GetModuleCount({0}, {1}, {2})) |
3 | 2 | Function | Dbo.get_GetFunctionCount({0},{1},{2})(Dbo.get_GetFunctionCount({0}, {1}, {2})) |
这给我们带来了巨大的好处,可以满足我们的要求.现在我们可以(This gives us significant benefits to complete our requirements. Now we can)
- 为每个项目写不同的业务以计算数量(Write distinct business to each items to calculate count)
- 隔离该错误,因为我们知道它必须是函数,因为它正在计算计数(Isolate the bug as we know that it has to be the function since that is calculating the count)
- 错误修复很容易,我们只需要修补功能并仅部署该功能(Bug fixing is easy, we only need to patch the function and deploy that function only)
- 同样,在每个菜单上都可以轻松进行更改(Similarly changes are easy to do on each individual menu)
- 由于我们使用的是自然编译的SQL函数,因此性能不会受到影响(Performance won’t be compromise as we are using SQL Functions which are compiled in nature)
- 现在,将计数减少到菜单项已是小菜一碟(Detaching count to a menu item is now a piece of cake)
- 现在,将计数添加到新菜单变得非常容易,因为我们只需要创建新功能并将其与菜单关联即可.甚至可以在生产现场完成此任务.(Attaching count to a new menu has now become very easy as we only need to create new function and simply associate it with the menu. This task even can be done at production site.) 这些函数的参数至关重要,因为这些参数将充当这些函数的上下文.他们将帮助他们确定从何处调用,如何调用和/或是否需要任何特殊逻辑.例如,这里的LoginId可能很棘手,因为计数可能取决于各个用户的业务逻辑.如果一个功能已被确定为所有菜单项的灵丹妙药,那么在这种情况下,功能ID将是决定该功能从何处调用的关键参数.(Parameters to these functions are critical as these parameters will act as context to these function. They will help them decide from where they have invoked, how they have invoked and/or do they require any special logic. For example LoginId can be tricky here as the count might depend upon individual user business logic. In case if a single function has been decided as silver bullet for all menu items, in that case function id would be a critical parameter for a function in deciding from where it has been invoked.)
现在,我们需要一种机制来加载单个用户的菜单项,执行与菜单相关的所有功能,将结果存储为XML并传递给应用程序,从而完成了所有工作.(All we now need a mechanism to load the menu items of an individual user, execute all the functions associated with the menu, store the result in XML and pass to application and we are all done.)
XML格式(XML)
与其以表格格式返回结果,我们选择以XML形式返回.原因是与其他格式相比,XML以更好的方式表示层次结构(例如Menu).其次,在客户端迭代xml很方便,因为它几乎表示相同的树结构.由于SQL Server对XML的良好支持,我们决定在数据库层生成XML,但是选择它的方式是,也可以在业务层生成相同的XML.(Instead of returning result in tabular format we choose to return as XML. The reason is that XML represent hierarchal structure (Menu for example) in much better way if compared to other formats. Secondly it would be handy at client side to iterate xml as it almost represent the same tree structure. We decided to generate XML at Database layer because of good xml support at SQL Server but its matter of choice, one can generate the same XML at Business Layer as well.)
<r>
<n t="0_1" v="24">
<n t="0_2" v="58">
<n t="0_3" v="74"/>
</n>
</n>
</r>
如果我们仔细查看xml,我们可以看到为减少xml大小所做的努力.这样做是为了减少每N分钟从服务器到浏览器浮动的数据大小. n在这里代表菜单节点.内部n表示菜单内的菜单,依此类推. t表示将用于精确识别树菜单节点的菜单键. v表示我们将与菜单树节点关联的值.空v表示没有值,这自然意味着不应该更新.(If we closely look at the xml we can see the efforts that have been put to decrease the xml size. This is being done to reduce the data size floating from server to browser every N Minutes. n represent here a menu node. an inner n means a menu inside a menu and so on. t represent the menu key that will be use to precisely identify the tree menu node. v represent a value that we will be associated with the menu tree node. An empty v means no value which naturally means should not be updated.)
动态SQL(Dynmic SQL)
我们认为将SQL函数附加到单个菜单项是一个不错的主意,因为它提供了极大的维护灵活性,修改,新添加,删除,错误修复,可以非常快速地完成业务更改而不会影响整个系统.但是这里面临的挑战是如何开发函数执行机制而又不引起明显的性能影响.一种想法是编写一些迭代逻辑,依次执行该函数并将结果存储在某个位置.我们通过消除迭代来改进了这种想法,并构建了一个动态sql(Attaching SQL functions to individual menu item we think is an elegant idea as it provides enormous maintenance flexibility, modifications, new additions, removal, bug fixing, business changes can be done very quickly without impacting the whole system. But the challenge here is how to develop function execution mechanism without causing significant performance impact. One idea was to write some iterative logic which in turn execute the function and store result at some place. We have improved this idea by eliminating the iteration and built a dynamic sql like this)
SELECT <HardcodeValue1>, <HardcodedValue2>, dbo.get_xxxx(HardcodeValue1, HardcodeValue2,..)
UNION ALL
SELECT <HardcodeValue1>, <HardcodedValue2>, dbo.get_xxxx(HardcodeValue1, HardcodeValue2,..)
....
上面的方法将为我们提供一个SQL,该SQL仅执行一次,并以表格结构形式返回结果.现在,该表格结构在每个菜单项上都有编号.现在,一个简单的临时表可以保存这些值,如下所示.现在,此临时表非常有用,因为这样我们就可以一次性完成每个菜单项的计数值更新,而无需任何迭代循环.(Above approach will give us a single SQL that will be executed only once and will return result in a tabular structure. This tabular strucure now has number against each menu item. A simple temporary table can now hold these values as shown below. This temporary table is now of great help as through this we can update countvalues against each menu item in one go that is without any iterative loops.)
分层XML生成(Hirarical XML Generation)
是的,SQL Server具有强大的本机xml支持.但是对于我们来说,这是一个挑战.由于我们的菜单结构是层次结构,并且我们声明的XML本质上也是嵌套的,因此我们需要一种在XML中具有嵌套元素的机制,SQL SERVER不直接支持该机制.这需要我们专门构建一个功能来完成这项工作.我们为xml中的生成嵌套元素设计了以下机制(Yes, SQL Server has great native xml support. But in our case there is a challenge. since our menu structure is hierarchal and our stated XML is also nested in nature hence we required a mechanism to have nested elements in our XML which is not directly supported by SQL SERVER. This required us to built a function specifically to do this job. We devised following mechanism for generative nested elements in our xml)
SELECT
isnull(Unique_id,'') as 't',
isnull(n.value,'') as 'v',
CASE WHEN IsNull(ParentFunctionId,0)=@FunctionId
THEN dbo.DocGet_XMLNode(@MENUTBL, FunctionId)
END
FROM @MENUTBL as n
WHERE IsNull(ParentFunctionId,0)=@FunctionId
FOR XML AUTO, TYPE
业务层(Business Layer)
提供的样本不需要隔离的业务层.由于我们已将ASP.NET MVC用于示例,因此可以将控制器视为业务层.现在,该层的职责是调用数据库组件,获取所需的xml并将结果返回给应用程序.这一切都可以通过Controller Actions完成.同样,出于说明目的,将简单的ADO.NET用于数据库访问.我们想在这里提到的一件事是,该层也可以用于生成所需的XML(当前正在数据库层完成).现在这是一个选择问题.我们使用数据库是因为它对XML的强大支持. SELECT FROM FOR XML AUTO是一种强大的方法,可以快速生成XML,因为已经存在一种机制,这就是我们不对其进行重新设计的原因.(The sample provided does not require an isolated business layer. Since we have use ASP.NET MVC for the sample so a controller can be treated as business layer. The responsibility of this layer now is to invoke the Database Components, get the required xml and return the result back to application. It has all being done using Controller Actions. Similarly for illustrative purpose simple ADO.NET is used for Database access. One thing that we would like to mention here is that this layer can also be used for generating the required XML (Which is currently being done at database layer). This is a matter of choice now. We used database because of its great support in XML. A SELECT FROM FOR XML AUTO is a powerful method that generates XML fast, since a mechanism is already present that’s why we did not re-engineer it.)
表示层(Presentation Layer)
ASP.NET MVC非常适合构建出色的Web应用程序,它与jQuery紧密集成,并轻松支持第三方工具.我们已经使用DEVEXPRESS树控件MVC扩展来生成菜单. jQuery用于AJAX调用和客户端树更新.(ASP.NET MVC is great in building cool web applications, it has tight integration with jQuery and easily support third party tools. We have used DEVEXPRESS Tree control MVC Extension for menu generation. jQuery is used for AJAX calls and client side tree update.)
使用代码(Using the code)
如上所述,所有这些框架的关键都在数据库层. DocGet_MenuXML存储过程是Heart,因为它拥有所有菜单结构,构建用于执行关联功能的动态sql,最后生成所需格式的XML.现在,让我们剖析DocGet_MenuXML存储过程.(As already stated above that the key to all this framework is at the database layer. DocGet_MenuXML stored procedure is the Heart as it holds all menu structure, build the dynamic sql for executing the associated functions and finally generate the XML in required format. Now lets dissect the DocGet_MenuXML Stored Procedure.)
DocGet_MenuXML(DocGet_MenuXML)
存储过程首先声明变量.重要的变量之一是(The Stored Procedure begins by declaring variables. One of the important variable is) @MENUTBL
因为此表将保存所需的要返回的菜单结构以及value字段,该字段将存储与菜单项关联的数字.这里我们需要记住,菜单结构取决于用户角色和权限.因此,仅需要获得用户有权使用的那些菜单项.此外,随着时间的流逝,菜单项也变得过时并处于活动状态.我们还需要过滤它们.这个(as this table will hold the required menu structure to be returned plus value field which will store the number associated with the menu item. We need to remember here that a menu structure is dependent upon user roles and rights. So it is necessary to get only those menu items for which a user has rights. In addition as the time pass menu items also become obsolete and become in active. We also need to filter those as well. This) @MENUTBL
做所有这些工作.(do all these jobs.)
SP的摘录下方显示了如何检索所有活动功能并将其存储在(Below excerpt from the SP shows how all active functions has been retrieved and stored in the) @MNUTBL
.(.)
WITH MENUHIRARCHY (FunctionParentId, FunctionId, MenuDisplayText, Level, countfunction)
AS
(
SELECT e.functionparentid, e.FunctionId, e.MenuDisplayText, e.Level, e.countfunction
FROM SEC_FUNCTION AS e
WHERE 1=1
and e.functionparentid is null
UNION ALL
SELECT e.functionparentid, e.FunctionId, e.MenuDisplayText,e.Level, e.countfunction
FROM SEC_FUNCTION AS e
INNER JOIN MENUHIRARCHY M on M.functionId = e.functionparentId
WHERE 1=1
AND e.functionIsActive=1
AND e.functionIsActive=1
)
INSERT INTO @MENUTBL
(
UNIQUE_ID,
PARENTFUNCTIONID,
FUNCTIONID,
Level,
MenuDisplayText,
countfunction
)
SELECT DISTINCT '0_'+CAST(FunctionId as varchar(10)),FunctionParentId, FunctionId, Level, MenuDisplayText, countfunction
FROM MENUHIRARCHY;
如您所见,通过在功能ID中预先添加0来生成唯一ID.这只是为了向您显示也可以以这种方式生成自定义唯一ID.(As you can see a unique Id is being generated by pre-appending 0 in the functionid. This is just to show you that a custom unique Id can also be generated in this manner.)
现在的下一步是动态构建SQL查询,如上所述. SP的摘录下面显示了如何构建动态SQL查询.这里要了解的一件事是where子句.请理解,每个菜单项都不必具有与之关联的计数功能,因为企业只能要求将菜单项计数到特定菜单. where子句过滤所有不具有关联计数功能的菜单项.还要仔细看看我们如何将参数传递给函数.这里的一个限制是参数集对于所有函数都是恒定的,可以通过将每个参数对每个函数的所有参数存储在表及其解析机制(从中获取这些参数的值)中来避免这种限制,但是这不是主题这里.(The next step now is to built the SQL Query dynamically as briefly explained above. Below excerpt from SP shows how dynamic SQL query has been built. The one important thing to understand here is the where clause. Do understand that it is not necessary that each menu item must have a count function associated with it because business can ask count menu items to specific menus only. The where clause filtering all those menu items that do not have associated count function. Also take a closer look of how we passed the parameters to the function. The one limitation here is that parameter set is constant to all functions, this limitation can be avoided by storing all the parameters against each function in a table and their resolution mechanism (from where we get the values to these parameters) but this is off topic here.)
SELECT @tsql = COALESCE(@tsql + ' UNION ALL ', 'INSERT INTO ##LocalTempMenuTable(ProjectID, FunctionID, value) ') + 'SELECT ' + cast(ProjectID as varchar(10)) + ',' + cast(FunctionID as varchar(10)) + ',' + Replace(Replace(Replace(CountFunction, '{0}', ProjectID), '{1}', FUNCTIONID), '{2}', @p_ContactID)
FROM @MENUTBL
WHERE CountFunction IS NOT NULL;
执行步骤(Execution step of) @TSQL
简单. sql将被执行,结果将存储在临时表中.(is easy. The sql will be executed and the result will be stored in temporary table.)
EXEC SP_EXECUTESQL @TSQL;
现在我们需要更新我们的价值->(Now we need updated our value->) @MENUTBL
,这只是小菜一碟,因为我们只需要一个联接即可将所有功能值更新为与其关联的菜单项.看看下面我们是如何做到的(, its a peice of cake now as we just need a join to update all functions value to their associated menu items. See below how we did it)
UPDATE @MENUTBL
SET value=CAST(m.value as varchar(20))
FROM @MENUTBL a
INNER JOIN ##LocalTempMenuTable m on a.functionId = m.functionId and a.ProjectId = m.ProjectId;
现在它生成XML的最后一步,我们已使用FOR XML AUTO,TYPE以所需格式生成XML. DocGet_XMLNode用于创建嵌套元素,因为我们的xml是自然嵌套的.(The last step now it generate XML, we have used FOR XML AUTO, TYPE for generative XML in the required format. DocGet_XMLNode is used for creating nested elements because our xml is nested in nature.)
SET @xml =
(
SELECT
IsNull(Unique_id,'') as 't',
Isnull(n.value,'') as 'v',
dbo.DocGet_XMLNode(@MENUTBL, FunctionId)
FROM @MENUTBL n
where 1=1
AND Level = 1
FOR XML AUTO, TYPE
);
SET @p_Outstring = '<r>'+CONVERT(VARCHAR(max), @xml, 1)+'</r>';
DocGet_MenuXML
在这里结束.现在让我们看看我们如何创建函数(ends here. Now let’s see how we created the function) get_GetAreaCount
这是"区域"菜单项的返回计数.该函数只是一个示例,实际上并没有做任何事情,只是向您展示如何自行构建复杂的函数.(which is returning number count for Area menu item. The function is just a sample and does not do anything in real, it is just to show you how you can build complex functions on your own.) get_GetAreaCount
只是在这里返回一个随机值.(is simply returning a random value here.)
ALTER FUNCTION [dbo].[get_GetAreaCount](@p_Param1 int, @p_Param2 int, @p_Param3 int)
RETURNS INT
AS
BEGIN
declare @Count INT = NULL
-- SELECT @Count = COUNT(DISTINCT FUNCTIONID)
--FROM SEC_FUNCTION
-- WHERE Functionid = @p_Param2
SELECT @Count = cast(rndResult * 100 as int)
FROM RandomView
return @Count
END
HomeController-> GetServerResponse(HomeController->GetServerResponse)
应用程序启动对HomeController->的AJAX调用(Application initiates AJAX call to HomeController->) GetServerResponse
行动.下面是代码片段的摘录,代码是不言自明的.只需创建数据库连接,创建命令对象并执行(action. Below is the excerpt of the code fragment and the code is self explanatory. It simply create a database connection, create a command object and execute the) DocGet_MenuXML
SP,然后将内容返回给应用程序.(SP and return the content back to application.)
public ActionResult GetServerResponse()
{
SqlConnection connection = null;
try
{
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
string outXMLString = string.Empty;
connection = new SqlConnection(connectionString);
using (SqlCommand cmd = new SqlCommand("DocGet_MenuXML", connection))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@p_ContactID", System.Data.SqlDbType.Int));
cmd.Parameters["@p_ContactID"].Direction = System.Data.ParameterDirection.Input;
cmd.Parameters["@p_ContactID"].Value = 1;
SqlParameter outparam = cmd.Parameters.Add(new SqlParameter("@p_Outstring", System.Data.SqlDbType.VarChar, 8000));
outparam.Direction = System.Data.ParameterDirection.Output;
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
outXMLString = Convert.ToString(cmd.Parameters["@p_Outstring"].Value);
}
ViewBag.MenuXML = outXMLString;
return Content(outXMLString);
}
catch (System.Data.DataException e)
{
if (connection != null)
if (connection.State != System.Data.ConnectionState.Closed)
connection.Close();
throw new Exception(e.Message);
}
}
_Layout.cshtml(_Layout.cshtml)
这是表示层的核心部分,它首先每N秒/分钟设置一次计时器挂钩并调用(this is core part of presentation layer, it first set timer hook for every N seconds/minutes and invoke) getCountStatus()
功能.(function.)
window.setInterval(function () {
getCountStatus();
}, 1000 * 10 * 1.25); //where X is your every X minutes
getCountFunction
调用AJAX调用,接收menuXML字符串,然后将xml字符串解析为XML对象.成功解析后,如果记住,它将获取我们xml的根节点" r",并将其传递给(invoke AJAX call, receive the menuXML string, parse the xml string into XML object. Upon successfully parsing it gets the root node of our xml which is “r” if remember and pass it to) MenuIterator
功能.(function.)
var actionUrlGetServerResponse = '@Url.Action("GetServerResponse", "Home")';
function getCountStatus() {
$.get(actionUrlGetServerResponse, function (projectTransmittalStatus) {
var menuXML = '@ViewBag.MenuXML';
$xmlDoc = $($.parseXML(projectTransmittalStatus));
var rootNode = $xmlDoc.find("*").eq(0);
MenuIterator($(rootNode));
});
}
MenuIterator
本质上是一个迭代器.它在xml中找到所有n个节点.对于每个xml节点,它通过查看t属性来获取密钥.使用此键搜索DevExpress树控件并找到相应的节点.成功识别节点后,应用程序将使用正则表达式来识别树节点文本中已经存在的任何数字.这很棘手,因为正确处理可能会导致每个AJAX调用中的"()“串联.我们使用正则表达式来标识菜单文本是否已更新.如果已更新,则我们仅更新菜单文本中的数字.如果不是,我们将更新该区域的文本(9)(is an iterator in nature. It finds all n nodes in the xml. For each xml node it gets the key by looking at t attribute. using this key it search for DevExpress tree control and find the corresponding node. Upon successfully identifying the node application uses regual expression to identify any number already present in the tree node text. There is tricky because in correctly handling may result concatenation of “()” on every AJAX Call. We used regular expression to identify that menu text has already been updated or not. If it has been updated then we updated only number in the menu text. If it is not then we update the text like this Area (9))
function MenuIterator($currentXMLNode) {
if ($currentXMLNode != null) {
$currentXMLNode.find('n').each(function (childXMLNode) { //'n'
if (childXMLNode != null) {
var menuText = $(this).attr('t');
var node = tvFunction.GetNodeByName(menuText);
if (node != null) {
//console.log("INFO", "node Value..." + node.GetText);
var nodeTotal = $(this).attr('v');
console.log("INFO", "nodeTotal" + nodeTotal);
if (nodeTotal != '') {
var re = new RegExp(/\d+/g);
var nodeText = node.GetText();
console.log("INFO", "nodeText = " + nodeText);
var m = re.exec(nodeText);
if (m != null) {
nodeText = nodeText.replace(re, nodeTotal);
console.log("INFO", "Matched" + nodeText);
}
else {
nodeText = nodeText + '(' + nodeTotal + ')';
console.log("INFO", "Not Matched Value..." + nodeText);
}
node.SetText(nodeText);
}
}
else {
//console.log("INFO", "node Value NULL " + menuText);
}
}
});
}
}
结论(Conslusion)
本文中阐述的方法不仅有助于构建具有相似要求的应用程序,还可以用于需要动态绑定代码的其他领域(The approach formulated in this article not only help building applications which have similar requirements but also can be used in other areas where code need to be binded dynamically)
历史(History)
第一版-0.1-2014年7月20日(First version - 0.1 - 20-Jul-2014)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
XML HTML C# .NET Visual-Studio Ajax VS2010 ASP.NET Design DevExpress 新闻 翻译