我已经看到了将常量添加到javascript文件中的问题的有用答案,因此它可以与剃刀视图一起使用:Share constants between C# and Javascript in MVC Razor
我希望能够做同样的事情,除了定义枚举,但我不知道如何将C#Enum转换为javascript中的常量。
关闭GetType(),似乎没有办法实际获得常量值。
答案 0 :(得分:11)
我从几个人的答案中得到了一个混合物并编写了这个HtmlHelper扩展方法:
public static HtmlString GetEnums<T>(this HtmlHelper helper) where T : struct
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.AppendLine("<script type=\"text/javascript\">");
sb.AppendLine("if(!window.Enum) Enum = {};");
var enumeration = Activator.CreateInstance(typeof(T));
var enums = typeof(T).GetFields().ToDictionary(x => x.Name, x => x.GetValue(enumeration));
sb.AppendLine("Enum." + typeof(T).Name + " = " + System.Web.Helpers.Json.Encode(enums) + " ;");
sb.AppendLine("</script>");
return new HtmlString(sb.ToString());
}
然后您可以使用Razor语法调用该方法,如下所示:
@(Html.GetEnums<Common.Enums.DecisionStatusEnum>())
然后会吐出这样的javascript:
<script type="text/javascript">
if(!window.Enum) Enum = {};
Enum.WorkflowStatus = {"value__":0,"DataEntry":1,"SystemDecisionMade":2,"FinalDecisionMade":3,"ContractCreated":4,"Complete":5} ;
</script>
然后你可以在javascript中使用它,如:
if(value == Enum.DecisionStatusEnum.Complete)
由于检查了顶部的属性(if(!window.Enum)
),这允许您为多个枚举调用它,它不会覆盖全局 Enum
变量,只是追加它。
答案 1 :(得分:7)
Dictionary
的{{1}}转换略有不同。
enum
您可以更进一步,传递public ActionResult DayOfWeekEnum()
{
var enumType = typeof(DayOfWeek);
var enumDictionary = enumType
.GetFields()
.Where(x => x.IsLiteral)
.ToDictionary(x => x.Name, x => (int)Enum.Parse(enumType, x.Name));
var json = new JavaScriptSerializer().Serialize(enumDictionary);
return JavaScript("var DayOfWeek = " + json + ";");
}
的命名空间并使用反射来查找类型。这将允许更通用的行动方法。
enum
答案 2 :(得分:6)
我之前使用的另一种方法是使用t4模板来完成这种工作。与t4mvc的工作方式类似,如果您知道如何使用它,这可能是一个非常强大的工具。
这个想法是在t4模板中,你在项目中搜索并查找枚举,当它找到一个枚举时,你需要模板来转换它并根据C#代码吐出一些javascript。我第一次使用T4Templates,它让我大吃一惊,并没有很多很好的资源,但它们可以是特殊的(参见t4mvc)
在你链接到的另一个问题中使用模板而不是控制器动作的优点是,t4模板引擎生成的文件是输出是常规js文件,可以像任何其他JavaScript文件一样提供/缩小,而不是要求MVC堆栈的开销来满足请求。
如果你有兴趣,我可能会挖掘一个例子。我可能没有在存储库中存放过。修改的
所以我挖了一个例子,我从它的原始形式编辑了一下,并没有测试它,但你应该得到这个想法。它有点长,所以我把它作为github gist。但我会在这里强调一些重要的块。
首先,T4 templates是Visual Studio中内置的模板引擎,控件块是用C#编写的(如果需要,可以用VB编写)。我不是想象中的专家,也不是自称是一个人,但我会分享我能做到的。因此,这些文件在visual studio项目中显示类似于其他“代码隐藏”类型的项目,您可以在其中展开.tt项目并查看其后面生成的模板文件。
让我们深入研究:
<#@ template language="C#v3.5" debug="true" hostspecific="true" #>
第一行设置控制块的语言。如你所见,我将使用C#。
<#@ output extension=".js" #>
接下来,我正在设置生成文件的扩展名。在这种情况下,我说我想生成一个.js
文件。因此,当我将此模板放入解决方案时,让我们enum.tt
,当我运行模板时,它将创建一个名为enum.js
的文件。您可以控制生成的文件(或多个文件)。例如,t4mvc可以选择生成一堆不同的文件(每个控制器一个)或生成一个t4mvc.cs
文件。
接下来,您将找到我需要使用的一堆程序集。一些更有趣的是:
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>
同样,我不是专家,但您可以在msdn网站上找到这些文档。这些提供了一些核心功能,可以访问/操作visual studio解决方案。
然后有一些相当无趣的进口。你会注意到控制块是由<# .. #>
分隔的(说实话,我真的不记得下一个字符的意义,它已经有一段时间了。)任何未包含在控制块中的内容都将直接写入到输出流。
这将我们带到将要编写的实际文件的开头:
window.Enum = function() {
this.__descriptions = [];
this.__ids = []
this.__last_value = 0;
}
window.Enum.prototype.add = function(name, val) {
if(val == undefined) val = ++this.__last_value;
this[name] = val;
this[val] = name;
this.__ids[val] = name;
this.__descriptions[val] = name.replace(/ShowWithEllipses$/,"...").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^\s+/,"");
return this;
}
window.Enum.prototype.describe = function(val) { return this.__descriptions[val] };
这里我只是制作一个简单的JavaScript Enum实现。没有声称它是最好的。但是它就是这样啊。 :)
<#
Prepare(this);
foreach(ProjectItem pi in FindProjectItemsIn(CurrentProject.ProjectItems.Item("Models"))) {
DumpEnumerationsFrom(pi);
}
#>
然后我们了解模板的内容。基本上它看起来在一个名为Models
的文件夹中。并挖掘并试图找到它能找到的任何枚举。如果是这样,它会调用以下方法:
void DumpEnumerationsFrom(ProjectItem file) {
var enumerations = new List<CodeEnum>();
FindEnum(file.FileCodeModel.CodeElements, enumerations);
if(enumerations.Count > 0) TT.WriteLine("// {0}",file.Name);
foreach(CodeEnum enumeration in enumerations) {
TT.Write("window.Enum.{0}=(new Enum())", enumeration.Name);
foreach(CodeElement ce in enumeration.Children) {
var cv = ce as CodeVariable;
if(cv == null) continue;
TT.Write("\r\n\t.add(\"{0}\", {1})", cv.Name, cv.InitExpression ?? "undefined");
}
TT.WriteLine(";\r\n");
}
}
它将生成如下所示的内容:
window.Enum.TheNameOfTheEnum = (new Enum()).add("Value1",1).add("Value2",2);
因此生成的JS文件直接基于c#项目中的枚举。
但是有一些限制。一个枚举必须位于项目中的文件中(不在引用的库中),至少使用此实现可能有更聪明的方法来执行它。每次更改枚举时,都必须重新运行模板(右键单击它并选择“运行自定义工具”)。
但是有一些优点,就像我之前提到的那样,生成的文件只是一个简单的js文件,所以可以组合并运行缩小。因为它只是一个文件,它可以托管在CDN上,就像我之前提到的那样,不需要点击MVC堆栈来提供请求。
无论如何,我并不是出于各种目的而说它是最好的主意,但在我看来这是一种未充分利用的方法。希望这可能有助于提供一些启示,并给你一个调查方向。