许多插件类型都会渲染内容,通常是HTML内容。虽然此内容可以完全在代码中生成,但插件也可以选择向小组件公开部分或全部渲染功能,并可以选择允许管理员使用小组件编辑器自定义插件 UI。
何时应使用小组件来渲染插件内容?
任何支持渲染内容的插件都可以选择使用小组件公开其部分或全部输出。可以使用此选项来简化渲染的定义,或使管理员能够使用小组件编辑器对渲染的内容进行更改。
通过小组件渲染插件定义的内容
要添加插件支持定义通过小组件进行内容渲染,插件必须实现 IScriptablePlugin 接口。IScriptablePlugin 接口在 Limyee.ScriptedContentWidgets.dll 的 Limyee.Extensibility.UI.Version1 命名空间中定义。实现此接口时,还需要将插件作为出厂默认小组件提供程序,并且插件使用的小组件实现脚本应存储在出厂默认提供程序实现的文件夹结构中(有关小组件源文件管理的更多详细信息,请参阅出厂默认小组件提供程序主题):
using System; using Limyee.Extensibility.UI.Version1; namespace Samples { public class SampleScriptablePlugin : IScriptablePlugin { // This must be unique for each widget defined by this plugin private readonly Guid _widgetId = new Guid("750364A8-CAA9-45D6-B14E-5D0F60BD70E2"); private IScriptedContentWidgetController _scriptController; #region IPlugin // ... #endregion #region IScriptedContentWidgetFactoryDefaultProvider // ... #endregion #region IScriptablePlugin public void Register(IScriptedContentWidgetController controller) { _scriptController = controller; var widgetOptions = new ScriptedContentWidgetOptions(_widgetId) { CanBeThemeVersioned = false, CanHaveHeader = false, CanHaveWrapperCss = false, CanReadPluginConfiguration = false, CanWritePluginConfiguration = false, IsEditable = false }; _scriptController.Register(widgetOptions); } #endregion // Get the name, description, cache configuration, CSS class using _scriptController.GetMetadata(_widgetId); // Get the header of the widget using _scriptController.RenderHeader(_widgetId, null) // Render the widget using _scriptController.Render(_widgetId, null) } }
单个插件可以定义多个小组件,以满足插件的特定渲染需求(一般实现另一个插件接口)。当调用 IScriptablePlugin 的 Register 方法时,插件应使用提供的控制器的 Register 方法注册每个小组件。控制器的 Register 方法使插件能够配置小组件的工作方式,详情如下:
- CanBeThemeVersioned 为 true 时,允许小组件拥有多个特定于主题的版本,这些版本将根据上下文适用的所选主题进行渲染。有关存储特定于主题的小组件版本的详细信息,请参阅出厂默认小组件提供程序主题。
- CanHaveHeader 为 true 时,允许此小组件有标头。如果启用了编辑,则此选项在编辑此小组件时自定义小组件的编辑器。如果插件永远不会使用标头,则最好将此选项设置为 false。
- CanHaveWrapperCss 为 true 时,允许此小组件有包装器 CSS。如果启用了编辑,则此选项在编辑此小组件时自定义小组件的编辑器。如果插件永远不会使用包装器 CSS,最好将此选项设置为 false。
- CanReadPluginConfiguration 为 true 时,允许小组件读取插件的配置(如果插件还实现了 IConfigurablePlugin)。由于脚本化的小组件无法公开其自己的配置,因此此选项使小组件能够使用 $limyee_v1_widget 的 GetString/Int/Bool/等等的方法,用于从有定义的插件中检索配置数据。
- CanWritePluginConfiguration 为 true 时,允许小组件编辑或保存插件的配置(如果插件还实现了 IConfigurablePlugin)。这允许小组件使用 $limyee_v1_widget 的 SetString/Int/Bool/等等的方法,用于保存配置数据,就像插件的配置编辑器。
- IsEditable 为 true 时,允许在小组件编辑器中编辑小组件。
- Extensions 允许添加私有小组件 API,这些 API 只能由注册定义的小组件使用。插件定义的小组件对常规小组件 API 仍可完全访问。要为单个小组件提供特定功能的访问权限,可以使用扩展选项仅向特定小组件公开私有 API。
定义私有小组件 API
使用小组件进行渲染的插件可以选择在注册小组件时,填充 Extensions 选项来向它定义特定的小组件私有 API。对上一示例版本修改,片段注册包括一个自定义扩展:
using System; using Limyee.Extensibility.UI.Version1; using System.Collections.Specialized; namespace Samples { public class SampleScriptablePlugin : IScriptablePlugin { private readonly Guid _widgetId = new Guid("750364A8-CAA9-45D6-B14E-5D0F60BD70E2"); private IScriptedContentWidgetController _scriptController; #region IPlugin // ... #endregion #region IScriptedContentWidgetFactoryDefaultProvider // ... #endregion #region IScriptablePlugin public void Register(IScriptedContentWidgetController controller) { _scriptController = controller; var widgetOptions = new ScriptedContentWidgetOptions(_widgetId) { CanBeThemeVersioned = false, CanHaveHeader = false, CanHaveWrapperCss = false, CanReadPluginConfiguration = false, CanWritePluginConfiguration = false, IsEditable = false }; widgetOptions.Extensions.Add(new SamplePrivateExtension()); _scriptController.Register(widgetOptions); } #endregion // Get the name, description, cache configuration, CSS class using _scriptController.GetMetadata(_widgetId); // Get the header of the widget using _scriptController.RenderHeader(_widgetId, null) // Render the widget using _scriptController.Render(_widgetId, null) } public class SamplePrivateExtension : IContextualScriptedContentWidgetExtension { #region IContextualScriptedContentWidgetExtension public string ExtensionName { get { return "private"; } } public object GetExtension(NameValueCollection context) { return new SamplePrivateExtensionApi(context); } #endregion } public class SamplePrivateExtensionApi { private NameValueCollection _context; public SamplePrivateExtensionApi(NameValueCollection context) { _context = context; } public string Value { get { return _context == null ? null : _context["Value"]; } } } }
在此示例中,注册插件定义的小组件(ID 是 _widgetId)时,在第 41 行同时也注册了一个私有 API:SamplePrivateExtension 类。SamplePrivateExtension 类使用 SamplePrivateExtensionApi 类定义其 API, API 名称是 private,该名称可供给其小组件使用 “$private” 的方式访问。SamplePrivateExtensionApi 上的任何公共属性和方法都向小组件公开,以便在实现此渲染的输出时使用。
请注意,私有扩展提供了上下文的 NameValueCollection。在渲染插件定义的小组件的内容脚本或标头时,插件可以提供一组上下文数据 NameValueCollection。此上下文数据传递到私有扩展,私有扩展可以使用上下文来更改其功能。
在上面的示例中,扩展希望接收名为 “Value” 的上下文值。定义小组件的插件将负责在渲染小组件时提供此值(有关示例,请参阅下一节)。
使用插件定义的小组件
现在,您已经拥有了由插件定义的一个或多个小组件,现在您可以使用这些插件来实现其他插件类型,并提供渲染输出。无论返回字符串或可以写入 TextWriter 的任何地方,插件都可以渲染其小组件。例如,使用前面的示例,插件可能有一个属性 Content,该属性是小组件应渲染的字符串。它可以传递上下文值并由定义为 _widgetId 的小组件来渲染,实现此属性后可供其他插件使用:
public string Content { get { return _scriptController.RenderContent(_widgetId, new NameValueCollection() { { "Value", "Test" } }); } }
在 _widgetId 定义的小组件中,调用 "$private.Value" 将返回 "Test"。小组件本身可以执行小组件支持的任何操作,包括创建 Ajax 回调,使用嵌入式文件等。
插件定义的小组件实现的注意事项
由插件定义的小组件可以执行常规小组件可以执行的所有操作,除了定义它们的插件启用的功能之外,还可以访问任何提供的私有 API。
实现插件定义的小组件时,最大的考虑因素是,您不可能只依赖于现有小组件 API 的上下文值。例如,除非小组件作为扩展执行 UI 请求,否则 $limyee_v1_blogPost.Current 可能永远不会有值,$limyee_v1_page.GetFormValue() 通常也没有值,因为他们依赖的是当前的 UI 请求,而不是 API 的上下文值。