Arquivo da categoria: Umbraco

Adicionando Atributos em Propriedades (C#)

Adicionando Atributos em Propriedades (C#)

Nem sempre é possível utilizar objetos complexos (classes) para incluir informações em propriedades de classes. Essa situação pode acontecer quando se está dando manutenção em um código que está amarrado a outro comportamento que não pode ser alterado.

No caso que deu origem à esse código, a classe possui uma dezena de propriedades públicas string que já estavam atreladas a outras classes e comportamento em outras partes do código. Não havia liberdade de criação de outras classes que incorporassem mais propriedades, então decidi enfeitar cada propriedade com atributos personalizados.

Dessa forma, foi possível no código acessar mais informações com base somente nessa propriedade string.

O código foi usado em uma aplicação de aluguel de móveis para eventos. Segue o código:

Classe do Objeto amarrado (Furniture.cs) com as classes de atributos no mesmo arquivo (para facilitar o entendimento)

using System;
using System.ComponentModel;
using System.Globalization;
using static ADX18.Library.Helpers.ADX18Helper;
 
namespace ADX18.Library.Models
{
    public class Furniture : iTestObject
    {
        [DisplayName("Mode Cupboard"),
            MemberPrice("225.50"),
            NonMemberPrice("247.50")]
        public string ModeCupboard_Quantity { get; set; }
        public string ModeCupboard_Colour { get; set; }
        [DisplayName("Poly Voge Chair"),
            MemberPrice("52.25"),
            NonMemberPrice("55.00")]
        public string PolyVogue_Quantity { get; set; }
        public string PolyVogue_Colour { get; set; }
        [DisplayName("Poly Vogue Stool"),
            MemberPrice("74.25"),
            NonMemberPrice("80.85")]
        public string PolyVogueStool_Quantity { get; set; }
        public string PolyVogueStool_Colour { get; set; }
        [DisplayName("Club Stool"),
            MemberPrice("77.00"),
            NonMemberPrice("82.50")]
        public string ClubStool_Quantity { get; set; }
        public string ClubStool_Colour { get; set; }
        [DisplayName("Ikon Dry Bar"),
            MemberPrice("165.00"),
            NonMemberPrice("177.65")]
        public string IkonDryBar_Quantity { get; set; }
        public string IkonDryBar_Colour { get; set; }
        [DisplayName("Ikon Meeting Table"),
            MemberPrice("143.00"),
            NonMemberPrice("154.00")]
        public string IkonMeetingTable_Quantity { get; set; }
        public string IkonMeetingTable_Colour { get; set; }
        [DisplayName("Ikon Illuminated Dry Bar"),
            MemberPrice("192.50"),
            NonMemberPrice("209.00")]
        public string IkonIlluminatedDryBar_Quantity { get; set; }
        public string IkonIlluminatedDryBar_Colour { get; set; }
        [DisplayName("Mode Dry Bar Table"),
            MemberPrice("104.50"),
            NonMemberPrice("108.90")]
        public string ModeDryBarTable_Quantity { get; set; }
        public string ModeDryBarTable_Colour { get; set; }
        [DisplayName("Mode Meeting Table"),
            MemberPrice("99.00"),
            NonMemberPrice("107.25")]
        public string ModeMeetingTable_Quantity { get; set; }
        public string ModeMeetingTable_Colour { get; set; }
        [DisplayName("Mode Coffee Table"),
            MemberPrice("93.50"),
            NonMemberPrice("100.65")]
        public string ModeCoffeeTable_Quantity { get; set; }
        public string ModeCoffeeTable_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeater_Quantity { get; set; }
        public string CubaLoungeOneSeater_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater Corner"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeaterCorner_Quantity { get; set; }
        public string CubaLoungeOneSeaterCorner_Colour { get; set; }
        [DisplayName("Cuba Lounge One Seater No Arm Rests"),
            MemberPrice("165.00"),
            NonMemberPrice("189.75")]
        public string CubaLoungeOneSeaterNoArms_Quantity { get; set; }
        public string CubaLoungeOneSeaterNoArms_Colour { get; set; }
        [DisplayName("Cuba Lounge"),
            MemberPrice("275.00"),
            NonMemberPrice("308.00")]
        public string CubaLounge_Quantity { get; set; }
        public string CubaLounge_Colour { get; set; }
        [DisplayName("Quattro Display Plinth 600mm"),
            MemberPrice("165.00"),
            NonMemberPrice("178.75")]
        public string QuattroDisplay600_Quantity { get; set; }
        public string QuattroDisplay600_Colour { get; set; }
        [DisplayName("Quattro Display Plinth 900mm"),
            MemberPrice("187.00"),
            NonMemberPrice("207.90")]
        public string QuattroDisplay900_Quantity { get; set; }
        public string QuattroDisplay900_Colour { get; set; }
        [DisplayName("Zig Zag Brochure Stand"),
            MemberPrice("115.50"),
            NonMemberPrice("123.20")]
        public string ZigZagStand_Quantity { get; set; }
        public string ZigZagStand_Colour { get; set; }
        [DisplayName("Carpet Floor Tiles"),
            MemberPrice("247.50"), NonMemberPrice("287.10"),
            NonMemberUnitPrice("31.90"),
            MemberUnitPrice("27.50")]
        public string CarpetFloorTiles_Quantity { get; set; }
        public string CarpetFloorTiles_Colour { get; set; }
        [DisplayName("Raised Floor Tiles"),
            MemberPrice("940.50"),
            NonMemberPrice("1188.00"),
            NonMemberUnitPrice("132.00"),
            MemberUnitPrice("104.50")]
        public string RaisedFloorTiles_Quantity { get; set; }
        public string RaisedFloorTiles_Colour { get; set; }
 
    }
// Classes de Atributos personalizadas
    public class NonMemberUnitPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public NonMemberUnitPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class NonMemberPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public NonMemberPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class MemberUnitPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public MemberUnitPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
    public class MemberPrice : Attribute
    {
        private decimal value;
        public decimal Value => value;
        public MemberPrice(string number)
        {
            value = decimal.Parse(number, CultureInfo.InvariantCulture);
        }
    }
 
 
}

Código de acesso desses atributos listados como um Dictionary<string,object> pois os valores retornados em cada atributo podem variar:

using ADX18.Library.Models;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
 
namespace ADX18.Library.Helpers
{
    public static class ADX18Helper
    {
      #region Furniture Helpers
        public interface iField { }
        public interface iTestObject { }
        //tweaked from https://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property 
        //and https://stackoverflow.com/questions/23329087/get-custom-attribute-from-specific-object-property-field
        public static Dictionary<string, object> GetAttributes<T>(this T source, Expression<Func<object>> field) where T : class
        {
            MemberExpression member = (MemberExpression)field.Body;
            if (member == null) { return null; }

            Dictionary<string, object> _dict = new Dictionary<string, object>();
            object[] propertyAttributes = typeof(T).GetProperty(member.Member.Name)
                .GetCustomAttributes(true);

            foreach (var propertyAttribute in propertyAttributes)
            {
                var attributeAttributes = propertyAttribute.GetType().GetProperties();
                foreach (var attributeAttribute in attributeAttributes)
                {
                    var propName = $"{propertyAttribute.GetType().Name}.{attributeAttribute.Name}";
                    if (!_dict.ContainsKey(propName) && attributeAttribute.Name != "TypeId")
                        _dict.Add(propName, attributeAttribute.GetValue(propertyAttribute, null));
                }
            }
            return _dict;
        }

        #endregion

    }
}

Com essas classes definidas, fica mais fácil acessar os atributos no Razor:

@model Furniture
@using ADX18.Library.Controllers
@using ADX18.Library.Models
@using ADX18.Library.Helpers;

                <div class="col-md-8">
                        @{
                            var modeCupboard = Model.GetAttributes<Furniture>(() => Model.ModeCupboard_Quantity);
                        }
                    <h5>@modeCupboard["DisplayNameAttribute.DisplayName"]</h5>
                    <p>
                        Available in four colours, this includes a lockable cupboard with shelves.<br />
                        L: 1200mm x W: 600mm x H: 1000mm
                    </p>
                    <div>
                        Member: <span class="memberPrice">$@modeCupboard["MemberPrice.Value"] each</span><br />
                        Non-member: <span class="memberPrice">$@modeCupboard["NonMemberPrice.Value"] each</span>
                    </div>
                    Quantity: <input type="text" name="ModeCupboard_Quantity" style="width: 10%;" />
                    <select name="ModeCupboard_Colour">
                        <option value="White">White</option>
                        <option value="Black">Black</option>
                        <option value="Red">Red</option>
                        <option value="Blue">Blue</option>
                    </select>
                </div>

Então, quando não puder mudar uma propriedade para incluir objetos complexos, use atributos personalizados!

Plugin para Umbraco 7 (belle)

Tutorial Umbraco 7 de Plugin Backoffice simples

Com o lançamento do Umbraco 7 em 21 de Novembro de 2013, a plataforma CMS do Umbraco mudou considerávelmente e deixou a vida dos usuários e, principalmente, dos desenvolvedores, muito mais fácil.

Não somente a interface administrativa (backoffice) foi bastante melhorada, mais fluida e compatível com aparelhos móveis.

Com isso, o tempo de desenvolvimento diminui bastante, facilitando bastante a vida. Agora, com o uso de simples Html5, CSS3, e Angular.js ficou fácil de criar extensões para a área administrativa.

Para demonstrar, vou mostrar a criação de uma extensão de backoffice simples de limite de carateres, e usei como exemplo o tutorial do Tim Geyssens Char Limit Property Editor for Umbraco Belle (http://www.nibble.be/?p=285)

Como comentei, o processo é simples:

  1. Para se criar um plugin, é necessário criar uma pasta dentro de App_Plugins
    Estrutura Umbraco
  2. Cria-se o package.manifest
    {
        propertyEditors: [
            {
    		alias: "Input.CharLimitEditor",
    		name: "Input Char limit",
    		"hideLabel": false,
          	"icon": "icon-stop-hand",
          	"group": "Common",
    		editor: {
    		view: "~/App_Plugins/Input.CharLimitEditor/views/view.html"
    		},
    		prevalues: {
    			fields: [
    				{
    					label: "Number of Characters",
    					description: "Enter the max number of characters allowed",
    					key: "limit",
    					view: "requiredfield",
    					validation: [
    						{
    							type: "Required" 
    						}						
    					]
    				}
    			]
    		}
            }
        ]
        ,
        javascript: [
            '~/App_Plugins/Input.CharLimitEditor/js/controller.js'
        ],
        css: [
        "~/App_Plugins/Input.CharLimitEditor/css/style.css"
      ]
    }
    
  3. O layout do Html
    
    
    <div ng-controller="Input.CharLimitEditorController" class="input-limit">
    	<span ng-if="model.config.limit >= 100">
           <textarea ng-model="model.value" ng-change="limitChars()" rows="10" class="umb-editor umb-textarea textstring"></textarea>
       </span>
       <span ng-if="model.config.limit < 100">
           <input ng-model="model.value" ng-change="limitChars()" type="text" class="umb-editor umb-textstring textstring" />
       </span>
       
       <span class="counter {{css}}">
        <i class="icon icon-{{icon}}"></i>
        <span ng-show="countLeft"> 
            <localize key="inputlimit_youhave">you have</localize> {{counter}} <localize key="inputlimit_charleft" >characters left</localize>
        </span>
        <span ng-show="maxReached">
            <localize key="inputlimit_limitReachedOnly">Only</localize> {{limit}} <localize key="inputlimit_limitReachedAllowed">allowed</localize>
        </span>
    </span>
    </div>
    
    
    
    

    Note que a tag

    <localize key="inputlimit_limitReachedOnly">Only</localize>

    está relacionada à Localização e não é obrigatória, mas ajuda se for publicar o pacote na comunidade

  4. (Opcional) Criar os arquivos de Idiomas para Localização
    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <language alias="pt_br" intName="Portuguese Brazil" localName="Portuguese Brazil" lcid="" culture="pt-BR">
      <creator>
        <name>Carlos Casalicchio</name>
        <link>https://www.ccasalicchio.com</link>
      </creator>
    
    
    <area alias="inputlimit">
        <key alias="youhave">Você tem</key>
        <key alias="charleft">caracteres sobrando</key>
        <key alias="limitReachedOnly">Somente</key>
        <key alias="limitReachedAllowed">caracteres permitidos!</key>
      </area>
    
    
    </language>
    
  5. O CSS (opcional)
    .input-limit .counter{
    	-webkit-transition: all 0.8s ease-in-out;
    	-moz-transition: all 0.8s ease-in-out;
    	-ms-transition: all 0.8s ease-in-out;
    	-o-transition: all 0.8s ease-in-out;
    	transition: all 0.8s ease-in-out;
    }
    
    .input-limit .thumb-up,.input-limit .alert,.input-limit .stop-hand{
    	padding: 5px 10px;
    }
    
    .input-limit .thumb-up{
    	background:#4FA23C;
    	color:#fff;
    }
    
    .input-limit .alert{
    	background: #B8860B;
    	color: #fff;
    }
    
    .input-limit .stop-hand{
    	color: #fff;
    	background: #DD793F;
    }
    
  6. E o mais importante, o controller.js (Angular.js)
    angular.module("umbraco")
    .controller("Input.CharLimitEditorController",
    	function ($scope) {
    		var limit = parseInt($scope.model.config.limit);
    		var thumbUp = "thumb-up", alert = "alert", warning = "stop-hand";
    		$scope.counter = limit - $scope.model.value.length;
    		$scope.limit = limit;
    		$scope.countLeft = true;
    		$scope.maxReached = false;
    		$scope.icon = thumbUp;
    		$scope.css = thumbUp;
    		
    		$scope.limitChars = function(){
    			$scope.counter = limit - $scope.model.value.length;
    			CheckChars();
    		};
    
    		function CheckChars(){
    			if($scope.model.value.length === 0){
    				$scope.countLeft = true;
    				$scope.maxReached = false;
    				$scope.icon = thumbUp;
    				$scope.css = thumbUp;
    			}
    
    			else if ($scope.model.value.length >= limit)
    			{
    				$scope.maxReached = true;
    				$scope.countLeft = false;
    				$scope.icon	= warning;
    				$scope.css = warning;
    				$scope.model.value = $scope.model.value.substr(0, limit );
    			}
    			
    			else if($scope.model.value.length < (limit/2)){ $scope.icon = thumbUp; $scope.css = thumbUp; $scope.maxReached = false; $scope.countLeft = true; } else if($scope.model.value.length > (limit/2)){
    				$scope.icon = alert;
    				$scope.css = alert;
    				$scope.maxReached = false;
    				$scope.countLeft = true;
    			}
    
    			else
    			{
    				$scope.icon = alert;
    				$scope.css = alert;
    				$scope.maxReached = false;
    				$scope.countLeft = true;
    			}
    		}
    		CheckChars();
    	});
    

Após isso, pode-se criar um pacote e submeter à comunidade, para que outras pessoas também usem, mas isso também é opcional. Este pacote, em particular está disponível em https://our.umbraco.org/projects/backoffice-extensions/input-character-limit/ e o código fonte no GitHub

Este plugin cria uma caixa de texto ou area de texto com um contador de caracteres, com várias chamadas visuais, afim de auxiliar o usuário a digitar o número de caracteres permitido.

Vazio

Em resumo, criar plugins para Umbraco ficou ainda mais fácil, e a curva de aprendizado ainda menor! Vale a pena investir nesse CMS.

Como criar um formulário de contato em Ajax para Umbraco

Como criar um formulário de contato em Ajax para Umbraco

por Carlos Casalicchio

Ao criar uma página responsiva em Umbraco rapidamente encontra-se algumas restrições relativas ao que a atual oferece. E, apesar da comunidade já ter desenvolvido várias coisas úteis, algumas vezes não encontramos o que precisamos.

Por esse motivo acabei por desenvolvendo um formulário de email simples que possibilite o envio de e-mails em Ajax, sem Postback da página.

Para tanto, criei o formulário na página (está fora do escopo discutir o html envolvido na criação do formulário) como na figura:

Como criar um formulário de contato em Ajax para Umbraco

Neste artigo, mostro como criar um formulário de contato em Ajax para Umbraco. O código do formulário é este:

Html

div class="contact_form">
    <div id="note"></div>
    <div id="fields">
        <form id="ajaxSendmail" action="">
            <input type="text" name="name" value="" placeholder="Name" />
            <input type="text" name="email" value="" placeholder="Email" />
            <textarea name="message" id="message" placeholder="Message"></textarea>
            <div class="clear"></div>
            <input type="reset" class="contact_btn" value="Clear Form" />
            <input type="submit" class="contact_btn send_btn" value="Send" />
            <div class="clear"></div>
        </form>
    </div>
</div>

CSS

#note {
            position: relative;
        }

            #note .notification_ok {
                position: absolute;
                top: 0;
                margin-top: 20px;
                padding: 7px 10px;
                text-align: center;
                text-transform: uppercase;
                background: #444;
                font-family: 'Lato', sans-serif;
                font-weight: 400;
                font-size: 14px;
                color: #fff;
            }

            #note .notification_error {
                position: absolute;
                top: 115px;
                font-family: 'Lato', sans-serif;
                font-weight: 400;
                font-size: 16px;
                color: #f00;
            }

Script AJAX

$("#ajaxSendmail").submit(function () {

            $(this).children().each(function () {
                $(this).css("border", "");
            });
            $('#note').html("");

            if ($("input[name='name']").val() === "" || $("input[name='email']").val() === ""
                || $("input[name='message']").val() === "") {
                $("#ajaxSendmail").children().each(function () {
                    if ($(this).val() === "") $(this).css("border", "2px solid #FF0000");
                });

                $('#note').html('<div class="notification_error">All values are required</div>');
                return false;
            }
            else {

                var str = $(this).serialize();

                $.ajax({
                    type: "POST",
                    url: "/SendMail.aspx",
                    data: str,
                    success: function (msg) {
                        // Message Sent - Show the 'Thank You' message and hide the form
                        if (msg.trim() == 'OK') {
                            result = '<div class="notification_ok">Your message has been sent. Thank you!</div>';
                            $("#fields").hide();
                        } else {

                            result = msg;
                        }
                        $('#note').html(result);
                    }
                });
                return false;
            }
        });

Para fazer o formulário funcionar, é preciso criar uma página macro (em Razor) que faça o processo de enviar o email:

Razor

@inherits umbraco.MacroEngines.DynamicNodeContext
@{
	var name = Request["name"];
	var email = Request["email"];
	var message = Request["message"];

	string host = "relay-hosting.secureserver.net",
                subject = "Contact Received from Site",
                body = "<h3>{0}</h3><p>From: {1}<br /><br /> Email: {2} </p><p>Message: {3}</p>",
                from = "mailer@zueuz.com",
                to = "email@myemail.com";
            int port = 25;

           System.Net.Mail.SmtpClient SmtpServer = new System.Net.Mail.SmtpClient(host, port);
           System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();

            mail.From = new System.Net.Mail.MailAddress(from, "Corporate Mailer");
            mail.To.Add(new System.Net.Mail.MailAddress(to, "Admin"));
            mail.Subject = subject;
            mail.Body = string.Format(body, subject, name, email, message);
            mail.IsBodyHtml = true;

	try
            {

                SmtpServer.Send(mail);
                <text>OK</text>;
            }
            catch (Exception e)
            {
                <text>@e.Message</text>;
            }

}

E também uma página sendmail
Template

Webforms do Umbraco

<%@  Master Language="C#" MasterPageFile="~/umbraco/masterpages/default.master" AutoEventWireup="true" %>

       <asp:Content ContentPlaceHolderID="ContentPlaceHolderDefault" runat="server">
           <umbraco:macro alias="Sendmail" runat="server"></umbraco:macro>
       </asp:Content>

Com esses componentes o formulário já envia e-mails

contact_form_success

contact_form_error

Criando um controle de Mídia Social para Umbraco v6+

Criando um controle de Mídia Social para Umbraco v6+

[ATUALIZADO] Motivação:  

Em WordPress e outras plataformas, há módulos/widgets/plugins que permitem que o usuário insira seus dados de mídia social e o site renderiza automaticamente.

Em Umbraco, não existia tal módulo. Então, criei um pequeno controle que guarda os dados de mídias sociais e renderiza numa página qualquer, como macro (Razor). Criando um controle de Mídia Social para Umbraco v6+ demonstra como faze-lo:

Criando um controle de Mídia Social para Umbraco v6+

Quando o usuário clica no icone (como na figura acima) uma nova janela se abre no site do usuário.

No controle, já inclui alguns sets de icones encontrados na internet (ver documentação). Em versões futuras, há interesse em programar de forma que quaisquer novos pacotes de icones sejam reconhecidos automaticamente.

Mas, no momento, o código ficou assim:

SocialMedia.ascx

<%@  Control  Language="C#"  AutoEventWireup="true"  CodeFile="Social  Media.ascx.cs"
        Inherits="UserControls_Social_Media"  ClientIDMode="Static"  %>
<strong>Style:
        <asp:DropDownList  ID="dpStyles"  runat="server"  AutoPostBack="true">
        </asp:DropDownList>
</strong><strong>
        <asp:CheckBox  ID="chkShowLabel"  runat="server"  Text="Show  Channel  Label"  OnCheckedChanged="chkShowLabel_CheckedChanged"  /></strong>

<table  style="width:100%;text-align:center;">
        <tr>
                <td>
                        <asp:Table  ID="tableLinks"  runat="server">
                        </asp:Table>
                </td>
                <td  style="vertical-align:top;  width:200px;text-align:left;">
                        <table>
                                <tr>
                                        <th>Theme  Name</th>
                                        <td><%=Name  %></td>
                                </tr>
                                <tr>
                                        <th>Description</th>
                                        <td><%=Description  %></td>
                                </tr>
                                <tr>
                                        <th>Creator</th>
                                        <td><%=Creator  %></td>
                                </tr>
                                <tr>
                                        <th>Created  Date</th>
                                        <td><%=Created  %></td>
                                </tr>
                                <tr>
                                        <th>Url</th>
                                        <td><a  href="<%=Url  %>"  target="_blank"><%=Url  %></a></td>
                                </tr>
                        </table>
                </td>
        </tr>
</table>

No code-behind (SocialMedia.ascx.cs)

using  Social_Media_Channels.Engine;
using  Social_Media_Channels.Engine.Utilities;
using  Social_Media_Channels.Entities;
using  System;
using  System.Configuration;
using  System.Web.UI;
using  System.Web.UI.WebControls;

public  partial  class  UserControls_Social_Media  :  System.Web.UI.UserControl,  umbraco.editorControls.userControlGrapper.IUsercontrolDataEditor
{
        private  Manager  _manager  =  null;
        static  Manager  _tmp  =  null;

        public  string  Name  {  get;  set;  }
        public  string  Description  {  get;  set;  }
        public  string  Creator  {  get;  set;  }
        public  string  Created  {  get;  set;}
        public  string  Url  {  get;  set;  }

        protected  override  void  OnInit(EventArgs  e)
        {
                string  ThemesFolder  =  ConfigurationManager.AppSettings["SocialMediaThemeFolder"]  ==  null  ?  null  :  ConfigurationManager.AppSettings["SocialMediaThemeFolder"].ToString();

                _manager  =  new  Manager(ThemesFolder,  false,  true);
                _tmp  =  new  Manager(ThemesFolder,  false,  true);

                if  (!Page.IsPostBack)
                {
                        _manager.ThemesDropdownList(ref  dpStyles,  _manager.Themes);
                }

                base.OnInit(e);
        }

        protected  void  Page_Load(object  sender,  EventArgs  e)
        {
                _manager.LoadSelectedTheme(dpStyles.SelectedValue);
                _manager.ShowLabels  =  chkShowLabel.Checked;
                _manager.RenderSocialItems(tableLinks,  _manager.CurrentTheme);

                //Theme  details
                Name  =  _manager.CurrentTheme.ID;
                Description  =  _manager.CurrentTheme.Description;
                Creator  =  _manager.CurrentTheme.Creator;
                Created  =  _manager.CurrentTheme.CreatedDate;
                Url  =  _manager.CurrentTheme.Url;
        }
        public  object  value
        {
                get
                {
                        foreach  (Channel  channel  in  _manager.CurrentTheme.Channels)
                        {
                                string  ctrl  =  "txt"  +  channel.ID;
                                channel.Url  =  ((TextBox)tableLinks.FindControl(ctrl)).Text;
                        }

                        string  json  =  JsonHelper.JsonSerializer<Manager>(_manager);
                        return  json;
                }
                set
                {
                        if  (value.ToString()  !=  string.Empty)
                        {
                                _tmp  =  (Manager)JsonHelper.JsonDeserialize<Manager>(value.ToString());
                                _manager.ShowLabels  =  _tmp.ShowLabels;
                                _manager.CurrentThemeID  =  _tmp.CurrentThemeID;

                                dpStyles.SelectedValue  =  _manager.CurrentThemeID;
                                chkShowLabel.Checked  =  _manager.ShowLabels;
                                LoadTheme();
                        }
                }
        }

        protected  void  chkShowLabel_CheckedChanged(object  sender,  EventArgs  e)
        {
                _manager.ShowLabels  =  (chkShowLabel.Checked);
        }

        private  void  LoadTheme()
        {
                _manager.LoadSelectedTheme(_tmp.CurrentThemeID);
                _manager.LoadSavedUrls(_manager.CurrentTheme,  _tmp.CurrentTheme);
        }
}

Já no front-end, foi criado um Macro usando Razor, de forma a renderizar os icones

@inherits  umbraco.MacroEngines.DynamicNodeContext
@using  umbraco.NodeFactory;
@using  umbraco.MacroEngines;
@using  System.Configuration;
@{
        var  nodeId  =  Parameter.NodeID;
        DynamicNode  node  =  Library.NodeById(nodeId);
        string  ThemesFolder  =  ConfigurationManager.AppSettings["SocialMediaThemeFolder"]  ==  null  ?  null  :  ConfigurationManager.AppSettings["SocialMediaThemeFolder"].ToString();
        Social_Media_Channels.Engine.Manager  manager  =  new  Social_Media_Channels.Engine.Manager(ThemesFolder,  false,  true);
        Social_Media_Channels.Engine.Manager  tmp;

        try
        {
                tmp  =  Social_Media_Channels.Engine.Utilities.JsonHelper.JsonDeserialize<Social_Media_Channels.Engine.Manager>(node.PropertiesAsList[node.PropertiesAsList.Count  -  1].ToString());
                manager.ShowLabels  =  tmp.ShowLabels;
                manager.LoadSelectedTheme(tmp.CurrentThemeID);
                manager.LoadSavedUrls(manager.CurrentTheme,  tmp.CurrentTheme);

        }
        catch  {              tmp  =  new  Social_Media_Channels.Engine.Manager(ThemesFolder,  false,  true);        }
}
<ul  class="social-channels"  id="social-channels">
        @if  (tmp.CurrentTheme  !=  null)
        {
                foreach  (Social_Media_Channels.Entities.Channel  channel  in  manager.CurrentTheme.Channels)
                {
                        if  (channel.Url  !=  "")
                        {
                                <li  class="social-channel">
                                        @Html.Raw(Social_Media_Channels.Engine.Manager.RenderRawA(manager.CurrentTheme,  channel))
                                        @if  (manager.ShowLabels)
                                        {
                                                <span  class="label"><a  href="@channel.Url"  target="_blank">@channel.Name</a></span>
                                        }
                                </li>
                        }
                }
        }
        else
        {
                <li  class="social-channel">No  Channels  were  found,  please  check  your  settings</li>
        }
</ul>

Assim, numa página, usase o macro

<%@  Master  Language="C#"  MasterPageFile="~/umbraco/masterpages/default.master"  AutoEventWireup="true"  %>

<asp:Content  ContentPlaceHolderID="ContentPlaceHolderDefault"  runat="server">
<!DOCTYPE  HTML>

<html>

<head>
	<meta  http-equiv="Content-Type"  content="text/html;  charset=UTF-8"  />
	<title>Social  Media  Channels  Example</title>
	<style>
		body{font-family:Candara;width:600px;margin:0  auto;}
		ul{list-style:none;}
	</style>
</head>

<body>

	<header>
		<nav>
			<ul>
				<li></li>
			</ul>
		</nav>
	</header>

	<section>

		<article>
			<header>
				<h2>Social  Media  Channels  Demo</h2>
				<umbraco:Macro  NodeId="1047"  Alias="SocialMediaChannels"  runat="server"></umbraco:Macro>
			</header>

		</article>

	</section>

	<aside>
	</aside>

	<footer>
		<p>Copyright  &copy;  2013  zuEuz  Tecnologia  &amp;  Negocios</p>
	</footer>

</body>

</html>

</asp:Content>

E fica renderizado desta forma

Criando um controle de Mídia Social para Umbraco v6+

 

Dentro do Umbraco, o gerenciador de Midias Sociais renderiza desta forma

Criando um controle de Mídia Social para Umbraco v6+

Visite a página do projeto no site Umbraco