Developer FAQ
How to add a custom widget to C1?
Answer:
Apart from a wide range of built-in C1 widget options, there is a possibility to add your own custom widget.
The main task is creation and registration of a Widget Provider.
The Widget Providers can expand on the list of visual widgets that Composite C1 supports in the Data Type editor and other guided scenarios. Widget Providers do not provide actual user interface elements and they are not a necessary step when creating new UI artifacts. Instead, they can emit Form UI Control markup which is used by Composite C1 when auto-generating forms.
Let’s look at the sample that adds a custom widget for fields in date and time format.
Note: Before compiling this sample, add references to the following components:
- System.Configuration
- Composite
- Microsoft.Practices.EnterpriseLibrary.Common
- Microsoft.Practices.ObjectBuilder
Here is the sample:
using System; using System.Collections.Generic; using System.Xml.Linq; using Composite.Functions; using Composite.Functions.Plugins.WidgetFunctionProvider; using Composite.C1Console.Security; using Composite.Core.Xml; using Composite.C1Console.Elements; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder; using Microsoft.Practices.ObjectBuilder; namespace SampleProvider { [ConfigurationElementType(typeof(MyWidgetFunctionProviderData))] class MyWidgetFunctionProvider : IWidgetFunctionProvider, IDynamicTypeWidgetFunctionProvider { // Called by the system to provide you with an object you can use to // Notify the system about ad hoc introduction of new widget functions // Not used in this sample. public WidgetFunctionNotifier WidgetFunctionNotifier { set { } } public IEnumerable<IWidgetFunction> Functions { get { // Return just one widget function here. yield return new SampleWidgetFunction(); } } public IEnumerable<IWidgetFunction> DynamicTypeDependentFunctions { get { yield break; } } } [Assembler(typeof(MyWidgetFunctionProviderAssembler))] public class MyWidgetFunctionProviderData : WidgetFunctionProviderData { // No custom configuration in this sample... } public sealed class MyWidgetFunctionProviderAssembler : IAssembler<IWidgetFunctionProvider, WidgetFunctionProviderData> { public IWidgetFunctionProvider Assemble(IBuilderContext context, WidgetFunctionProviderData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache) { return new MyWidgetFunctionProvider(); } } /// <summary> /// This class is a concrete windget function, returned by the provider. /// </summary> public class SampleWidgetFunction : IWidgetFunction { // Called by the system when Form UI Control markup is required from this widget function. // The parameters contain your "widget configuration". You can define your parameters using // the ParameterProfiles properties below. public XElement GetWidgetMarkup(ParameterList parameters, string label, HelpDefinition helpDefinition, string bindingSourceName) { return new XElement(Namespaces.BindingFormsStdUiControls10 + "DateTimeSelector", new XAttribute("Label", label), new XAttribute("Help", helpDefinition.HelpText), new XElement(Namespaces.BindingForms10 + "bind", new XAttribute("source", bindingSourceName))); } public string Name { get { return "SampleWidgetFunction"; } } public string Namespace { get { return "Sample.Widget.Namespace"; } } // This sample widget can handle string data public Type ReturnType { get { return typeof(string); } } public string Description { get { return "This is the description of the sample widget from our sample provider"; } } // No prameters used in this sample public IEnumerable<ParameterProfile> ParameterProfiles { get { yield break; } } // This returns a "security ID" for this widget function. // It permissions are attached to this widget function the object returned here is used to // identify those settings. public EntityToken EntityToken { get { return new SampleWidgetFunctionEntityToken(this.Name); } } } /// <summary> /// This class describes the sample widget functions "entity token" - an artifact /// used to identify data and elements in the security system. /// </summary> [SecurityAncestorProvider(typeof(NoAncestorSecurityAncestorProvider))] public class SampleWidgetFunctionEntityToken : EntityToken { private string _id; internal SampleWidgetFunctionEntityToken(string id) { _id = id; } public override string Id { get { return _id; } } public override string Source { get { return ""; } } public override string Type { get { return ""; } } // Responsible for serializing the state of this EntityToken as a string public override string Serialize() { return _id; } // Respinsible for deserializing the string return by the serializer above public static EntityToken Deserialize(string serializedEntityToken) { return new SampleWidgetFunctionEntityToken(serializedEntityToken); } } internal sealed class NoAncestorSecurityAncestorProvider : ISecurityAncestorProvider { public IEnumerable<EntityToken> GetParents(EntityToken entityToken) { yield return AttachingPoint.PerspectivesRoot.EntityToken; } } }Download the sample code
Code sample highlights
The provider class returns information about its widget functions through the Functions
property. A widget function is not known if it is not returned here.
The widget functions must have a unique namespace / name combination. If the system finds two or more functions with the same name, they are both ignored and a warning is written to the system log.
The GetWidgetMarkup
function is the “heart” of the widget function class. While all the properties defined on IWidgetFunction
serve declarative purposes, the GetWidgetMarkup
function “executes” the widget function. GetWidgetMarkup
must return an XElement
representing valid Form UI Control markup.
In the GetWidgetMarkup
function you can use some of already existing UI controls to build your widget.
In this example we've used the DateTimeSelector control to build a widget for a String
field.
Please, refer to the Composite configuration in ~\App_Data\Composite\Composite.config
:
<Namespace name="http://www.composite.net/ns/management/binding...">
To add a custom widget to C1 UI, take the following steps:
- Compile your code and place the assembly in
~\Bin
directory. - Register your provider in the Composite configuration in
~\App_Data\Composite\Composite.config
(see below).
Registering the provider in the Composite configuration
To register your provider in the Composite configuration file, add an <add />
element to the plug-ins list of the Composite.Functions.Plugins.WidgetFunctionProviderConfiguration
element. Below is how the sample provider shown above would look like.
<Composite.Functions.Plugins.WidgetFunctionProviderConfiguration> <WidgetFunctionProviderPlugins> <add type="SampleProvider.MyWidgetFunctionProvider, WidgetProvider" name="WidgetProvider" /> </WidgetFunctionProviderPlugins> </Composite.Functions.Plugins.WidgetFunctionProviderConfiguration>
Note: Please, make sure to set a correct value for the type
attribute of the add
tag.
type="Namespace_name.Class_name, Assembly_name”
and name
is an assembly name.