概述
NopCommerce源码架构详解-Nop多语言之绑定属性控制类型(AttributeControlType)详解。
内容
nop管理后台编辑商品时可以为每个商品增加多个属性,这种设计大大的提高的系统的可扩展性,这样可以自适应种类型的商品,而不用改数据库表结构,我们可以从下图中看到页面显示效果。

上图红框里面可以看有三个属性,我们可以看到这个属性的类型是不同的,第一个是选择时间,第二和第三个是下拉框选择。这是通过什么来实现的呢?
我们在后台设置时,每个属性会有一个字段表示属性的控制类型,如下图:

正是这个属性的控制类型,我们选择不同的类型,前台页面就会以同的形式的输入展示,在Nop里面这是一个枚举类型。
下面我们来看看它是的底层原理。
AttributeControlType在命名空间Nop.Core.Domain.Catalog里面。
AttributeControlType.cs:
namespace Nop.Core.Domain.Catalog { /// <summary> /// Represents an attribute control type /// </summary> public enum AttributeControlType { /// <summary> /// Dropdown list /// </summary> DropdownList = 1, /// <summary> /// Radio list /// </summary> RadioList = 2, /// <summary> /// Checkboxes /// </summary> Checkboxes = 3, /// <summary> /// TextBox /// </summary> TextBox = 4, /// <summary> /// Multiline textbox /// </summary> MultilineTextbox = 10, /// <summary> /// Datepicker /// </summary> Datepicker = 20, /// <summary> /// File upload control /// </summary> FileUpload = 30, /// <summary> /// Color squares /// </summary> ColorSquares = 40, /// <summary> /// Image squares /// </summary> ImageSquares = 45, /// <summary> /// Read-only checkboxes /// </summary> ReadonlyCheckboxes = 50, } }
依次对应下拉框,单选按钮…… Nop后台是用的UI框架Kendo UI,列表对应的是里面的kendoGrid组件。
下面我们来看看视图文件具体代码实现。
绑定属性控制类型(AttributeControlType)对应视图文件:
\src\Presentation\Nop.Web\Administration\Views\Product\_CreateOrUpdate.ProductAttributes.cshtml:

采用是变量AttributeControlType来绑定下拉列表,AttributeControlType是结合razor语法动态定义的。

上面代码主要作用是通过拼接一段js代码,来定义一个js变量。
注意:
上面用了标签,这样表示是一段文本不作Razor语法表达式解析,如果不用把其内容包裹起来,会报错的。
不信的同学可以试试。
因为里面有花括号和一些特殊字符,而这些又正好是在Razor里面有意义的。我们知道在Razor视图里面要表示纯文本有两种方法
1、用“@:”开头(单行)
2、用标签包裹(多行文本)
接下来我们查看一下页面显示在浏览器中的源码。

可以看到最终是一个json格式的数组。而这个数组的数据来源是通过调用AttributeControlType扩展方法实现的。
Nop.Web.Framework.Extensions:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj, bool markCurrentAsSelected = true, int[] valuesToExclude = null) where TEnum : struct { if (!typeof(TEnum).IsEnum) throw new ArgumentException("An Enumeration type is required.", "enumObj"); var localizationService = EngineContext.Current.Resolve<ILocalizationService>(); var workContext = EngineContext.Current.Resolve<IWorkContext>(); var values = from TEnum enumValue in Enum.GetValues(typeof(TEnum)) where valuesToExclude == null || !valuesToExclude.Contains(Convert.ToInt32(enumValue)) select new { ID = Convert.ToInt32(enumValue), Name = enumValue.GetLocalizedEnum(localizationService, workContext) }; object selectedValue = null; if (markCurrentAsSelected) selectedValue = Convert.ToInt32(enumObj); return new SelectList(values, "ID", "Name", selectedValue); }
可以从上面代码看到,ToSelectList是一个泛型方法,里面调用了Enum.GetValues返回对应枚举的所有值,并结合本地化多言服务LocalizationService转化成对应的语言。 在表LocaleStringResource详细记录了每种语言变量对应值。
你可以通过下面的sql语句查询本例涉及到的“全部属性控制类型”:
SELECT * FROM LocaleStringResource a WHERE a.LanguageId=2 AND a.ResourceName LIKE 'Enums.%'

注意:
Nop中针对枚举的语言资源都以“Enums.”开头是为了区分是枚举变量。
我们从Nop.Services.Localization.LocalizationExtensions里面针对枚举的扩展方法GetLocalizedEnum也能明白这个规律。
