Overview Overview AdvantageModule is an ASP.net user-control referred to as a "Module" that inherit from the specific class. These controls provide the front-end expression of content. When working with page-based "unstructured content", the information is supplied to the control based on an associated user-control that is registered with the module. The associate control is referred to as a "Dialog". A dialog is an ASP.net usercontrol that inherits from "AdvantageAttributeControl". Information is passed between the objects using the "Attributes" property of the controls of type "AdvantageAttributes". Dialog control Information is stored to the "Attributes" property Information is saved to the dialog using the "SaveDataToObject()" method. Information is loaded into the dialog using the "LoadDataFromObject(AdvantageAttributeArgs e)" method. AdvantageModule Information is retrieved using the "Attributes" property Steps Intro This guide provides a step-by-step walkthrough for creating an "AdvantageModule" with an associated dialog (AdvantageAttributeControl) designed to manage page-based content. This content refers to any data that is not used elsewhere in your application and only available in the page it has been created. 1. Create an AdvantageModule The first step in the process is to create a front-end expression user-control that inherits from AdvantageModule. 2. Develop a Dialog Control The first step in the process is to create an admin data entry user-control that inherits from AdvantageAttributeControl. 3. Binding information that needs to be passed from Dialog to Module Using the control.ascx file create the html control elements In the control.ascx.cs file complete the methods "LoadDataFromObject(AdvantageAttributeArgs e)" and "SaveDataToObject()" storing/retrieving the "Attributes" information to be passed to the expression module. 4. Retrieving Information stored from Dialog to Module Using the control.ascx file create the html display elements In the control.ascx.cs retrieve the "Attributes" information to be passed from the dialog module and bind to the appropriate element. 5.Register the Module/Dialog The final step in creating an module is to register within the system. Registration makes the mdoule available for use, linking it with the system's backend and frontend components. By following these steps—you can effectively set up an AdvantageModule for managing page content. Storing Data - Attributes Understanding AdvantageAttributes methods & properties Passing data between the administrative portal and the front end expression is used via the AdvantageAttributes. Storing information is done via the "Add" method. This method is overloaded allowing for native datatypes, as well as any class object that is serializable. Information is retrieved via the "GetAttribute" method. This method is overloaded allowing for native datatypes, as well as any class object that is serializable. Storage Object (Optional) The attributes from the dialog may be stored directly, however developers may find it coinvent and easier to code if you store to a class. The class must be serializable to be used. .csnamespace AdvantageClient { public enum eContentCardLayout { //If french, it will pickup the Localized entry, otherwise default [Description("Side by Side")] [LocalDescription("fr", "Côte à côte")] SideText =0, [Description("Below")] [LocalDescription("fr", "Below")] BelowText = 1, [Description("Overlay-small")] [LocalDescription("fr", "Superposition-petit")] OverlayTextSmall = 2, [Description("Overlay-Large")] [LocalDescription("fr", "Superposition-grande")] OverlayTextLarge = 3 } public class ContentCard { public string Content { get; set; } public int Id { get; set; } public string Category { get; set; } public eCategoryDisplay CategoryDisplay { get; set; } public string Heading { get; set; } public string SubHeading { get; set; } private AdvantageImage _image = null; public bool IsActive { get; set; } = true; public int SortOrder { get; set; } /// <summary> /// Get the image, and create a default with correct sizes if it doesn't exist /// </summary> /// <value>The image.</value> public AdvantageImage Image { get { if (_image == null) _image = LoadAdvantageImage(); return _image; } set { _image = value; } } public eContentCardLayout CardLayout { get; set; } = eContentCardLayout.SideText; public string Url { get; set; } private AdvantageImage LoadAdvantageImage() { var advantageImage = new AdvantageImage(); advantageImage.AddImageElement(new AdvantageImageElement() { ImageName = "Card Image", ImageSizeName = "Content Card" }); advantageImage.DefaultElementName = "Image"; return advantageImage; } } } Create A Dialog Control The dialog control provides the data-entry screen for the AdvantageModule front-end display. Create new User control that inherits from AdvantageAttributeControl Add a html binding in the .ascx file. .ascx<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ContentCardDialog.ascx.cs" Inherits="AdvantageClient.Modules_ContentCardDialog" %> <fieldset> <legend>Display</legend> <div class="form-row"> <label>Text Layout</label> <asp:DropDownList ID="ddlLayout" runat="server"> </asp:DropDownList> </div> </fieldset> <fieldset> <legend>Content Card</legend> <div class="form-row"> <label>Category</label> <asp:TextBox runat="server" ID="txtCategory"></asp:TextBox> </div> <div class="form-row"> <label>Category Color</label> <asp:DropDownList runat="server" id="ddlCategoryColor"/> </div> <div class="form-row"> <label>Heading</label> <asp:TextBox runat="server" ID="txtHeading"></asp:TextBox> </div> <div class="form-row"> <label>Sub-heading</label> <asp:TextBox runat="server" ID="txtSubheading"></asp:TextBox> </div> <div class="form-row btnAvailable"> <label>Navigation Url</label> <advantage:AdvantageSelectorLink runat="server" ID="lnkUrl" /> </div> <div class="form-row btnImageAvailable"> <label>Image</label> <advantage:AdvantageSelectorImage runat="server" ID="imgSelector" /> </div> <div class="form-row"> <label>Content</label> <Advantage:AdvantageEditor runat="server" id="edtContent" UseFieldSet="False" Height="300px"></Advantage:AdvantageEditor> </div> </fieldset> Bind html control content to the attributes. .ascx.csnamespace AdvantageClient { public partial class Modules_ContentCardDialog : AdvantageAttributeControl { /// <summary> /// Loads the data from object if it has been set, otherwise creates a new object. /// </summary> /// <param name="e">AdvantageAttributeArgs containing system information about the domain, language, etc.</param> protected override void LoadDataFromObject(AdvantageAttributeArgs e) { var myObject =(Attributes.GettAttribute<ContentCard>("ContentCard")); if (myObject == null) { myObject = new ContentCard(); myObject.CardLayout = eContentCardLayout.SideText; } ClientHelper.Enum_SetDropDownList<eContentCardLayout>(ddlLayout, myObject.CardLayout); ClientHelper.Enum_SetDropDownList(ddlCategoryColor, myObject.CategoryDisplay); txtCategory.Text = myObject.Category; txtHeading.Text = myObject.Heading; txtSubheading.Text = myObject.SubHeading; imgSelector.SetAdvantageImage(myObject.Image); lnkUrl.SetAdvantageLink(myObject.Url); edtContent.Content= myObject.Content; } /// <summary> /// Converts to object and saves it for later use in the front-end /// </summary> protected override void SaveDataToObject() { var myObject = new ContentCard(); myObject.CardLayout = ClientHelper.Enum_GetDropDownList<eContentCardLayout>(ddlLayout); myObject.CategoryDisplay = ClientHelper.Enum_GetDropDownList<eCategoryDisplay>(ddlCategoryColor); myObject.Category = txtCategory.Text; myObject.Heading = txtHeading.Text; myObject.SubHeading = txtSubheading.Text; myObject.Image = imgSelector.GetAdvantageImage(); myObject.Url = lnkUrl.GetAdvantageLink(); myObject.Content = edtContent.Content; Attributes.Add("ContentCard", myObject); } public override bool ValidateSave(out string message) { bool retval = true; message = string.Empty; if (string.IsNullOrEmpty(edtContent.Content)) { message = "Please enter Content.<br/>"; retval = false; } return retval; } } } Create Module The module control retrieves data set in the dialog and provides the front-end display. Create new User control that inherits from AdvantageModule Add a html binding in the .ascx file. .ascx<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ContentCard.ascx.cs" Inherits="AdvantageClient.Modules_ContentCard" %> <!-- register scripts to top of page --> <asp:PlaceHolder runat="server" id="phTop"> <style> .card { background-color: transparent !important; } </style> </asp:PlaceHolder> <advantage:AdvantageDisplayImage ID="imgOverLay" runat="Server" OnClientImageChange="CardSwapOverlay" style="display: none;"/> <asp:Panel runat="server" ID="pnlCardOverLay" cssClass="card card-overlay-bottom card-bg-scale h-300 " style="background-position: center left; background-size: cover;" Visible="False"> <!-- Card Image overlay --> <div class="card-img-overlay d-flex align-items-center p-3 p-sm-4"> <div class="w-100 mt-auto"> <div class="col"> <!-- Card category --> <asp:HyperLink NavigateUrl="#" CssClass="badge mb-2 text-white " runat="server" id="hypCategoryOverlay"><i class="fas fa-circle me-2 small fw-bold"></i><asp:Literal runat="server" id="litCategoryOverlay"></asp:Literal></asp:HyperLink> <!-- Card title --> <asp:PlaceHolder runat="server" id="phHeadingOverlay"><h2 class="text-white" runat="server" id="hHeading"><asp:HyperLink runat="server" id="hypActionOverlay" CssClass="btn-link text-reset stretched-link fw-normal"><asp:Literal runat="server" id="litHeadingOverlay"/></asp:HyperLink></h2></asp:PlaceHolder> <!-- Card info --> <div class="nav nav-divider text-white-force align-items-center d-none d-sm-inline-block"> <asp:PlaceHolder runat="server" id="phSubHeadingOverlay"><h6 class="card-text text-white fw-bold"><asp:Literal runat="server" id="litSubHeadingOverLay"/></h6></asp:PlaceHolder> <asp:Panel CssClass="card-body" id="pnlContentOverlay" runat="server" > <asp:Literal runat="server" id="litContentOverlay" /> </asp:Panel> </div> </div> </div> </div> </asp:Panel> <!-- Card item START --> <asp:panel id="pnlSideLayout" runat="server" Visible="False" CssClass="card mb-2 mb-md-4 contentCardContainer sideLayout"> <div class="row g-3 my-md-1 py-md-2 my-xl-2 py-xl-2 mb-4"> <div class="col-12 col-md-5 text-center px-0"> <advantage:AdvantageDisplayImage ID="imgDisplay" runat="Server" ImageCssClass="advantagePictureImage" CssClass="cardImage" /> </div> <div class="col-12 col-md-7 p-4 card-description-container test"> <asp:HyperLink NavigateUrl="#" CssClass="badge mb-2 " runat="server" id="hypCategory"><i class="fas fa-circle me-2 small fw-bold"></i><asp:Literal runat="server" id="litCategory"></asp:Literal></asp:HyperLink> <h4 class="cardTitle"><asp:HyperLink id="hypAction" CssClass="btn-link stretched-link text-reset fw-bold" runat="server"></asp:HyperLink></h4> <asp:PlaceHolder runat="server" id="phSubHeading"> <h6><asp:Literal runat="server" id="litSubHeading"></asp:Literal></h6> </asp:PlaceHolder> <!-- Card info --> <div class="cardInfo"> <asp:Literal id="litContent" runat="server" /> </div> </div> </div> </asp:panel> <!-- Card item START --> <asp:panel id="pnlBelow" runat="server" Visible="False" CssClass="card content-card"> <!-- Card img --> <div class="position-relative"> <advantage:AdvantageDisplayImage ID="imgDisplayBelow" runat="Server" ImageCssClass="advantagePictureImage rounded-3 h-300" CssClass="" /> <div class="card-img-overlay d-flex align-items-start flex-column p-3"> <!-- Card overlay Top --> <div class="w-100 mb-auto d-flex justify-content-end"> <%-- <div class="text-end ms-auto"> <!-- Card format icon --> <div class="icon-md bg-white bg-opacity-10 bg-blur text-white fw-bold rounded-circle" title="8.5 rating">8.5</div> </div>--%> </div> <!-- Card overlay bottom --> <asp:Panel runat="server" id="pnlCategoryBelow" CssClass="w-100 mt-auto"> <asp:HyperLink NavigateUrl="#" id="hypCategoryBelow" CssClass="badge mb-2 " runat="server"><i class="fas fa-circle me-2 small fw-bold"></i><asp:Literal runat="server" id="litCategoryBelow"></asp:Literal></asp:HyperLink> </asp:Panel> </div> </div> <div class="card-body px-0 pt-3"> <h5 class="card-title"><asp:HyperLink id="hypActionBelow" CssClass="btn-link stretched-link text-reset fw-bold" runat="server"><asp:Literal runat="server" id="litHeadingBelow"></asp:Literal></asp:HyperLink></h5> <h6><asp:Literal runat="server" id="litSubHeadingBelow"></asp:Literal></h6> <!-- Card info --> <asp:Literal runat="server" id="litContentBelow"></asp:Literal> </div> </asp:panel> <!-- Card item END --> <!-- Register scripts to bottom of page --> <asp:PlaceHolder runat="server" ID="phBottomScript"> <script> </script> </asp:Pla Bind attributes to the html control content. {ascx-cs} Register the module How to register a Module in Advantage CSP Go to Sytem Administrator > Modules > Modules The module should be available in your widgets list inside the page manager.