De façon détaillée:
Techniquement, un skin DotNetNuke est un User Control ASP.Net qui hérite de la classe abstraite DotNetNuke.UI.Skins.Skin.
La seule contrainte pour qu'un tel ascx fonctionne est qu'il hérite de la bonne classe et qu'il déclare au moins un contrôle serveur Html, de type <p>, <div>, <span> ou <td> ayant pour Id "ContentPane", qui sera le panneau par défaut accueillant les modules rajoutés à l'aide du panneau de contrôle, qui, si son emplacement n'est pas défini dans la skin, viendra se positionner en amont en début de page.
Pour un thème utilisable sur toute l'instance, il doit être positionné dans un répertoire portals/_default/Skins/<NomdelaSkin>/ , et ou de façon analogue dans le répertoire du portail pour un thème restraint à un portail spécifique.
Le seul fait de positionner un ascx dans un tel répertoire permettra de le faire apparaître dans les rubriques de sélection des thèmes disponibles. Ca ne garantira pas pour autant sa validité.
Comme il s'agit de concevoir le gabarit d'une page c'est à dire son contenu html à l'exception des modules qui seront positionnés dynamiquement, il existe un certain nombre de User Controls (fichiers ascx) fournis avec DNN et qui permettent d'intégrer les composants dynamiques courants de la page (menu, bouton de connexion etc...).
Ôn appelle ces contrôles des skin objects, il est possible d'en concevoir de nouveaux, et ceux par défauts sont accessibles dans les répertoires admin/Skins et admin/Containers.
Il est possible de les positionner depuis visual studio dans l'ascx d'un skin comme n'importe quel UserControl ASP.Net, par exemple en faisant un glissé déposé en mode design, ce qui aura pour conséquence de déclarer l'ascx à inclure sous forme de balise personnalisée au début de l'ascx principal (<%@ Register TagPrefix...) et de positionner cette balise à l'emplacement souhaité.
Les skins objects, en tant que classes .Net de contrôles, exposent un certain nombre de propriétés de personnalisation, souvent pour décrire la mise en forme du html qui sera généré, et notamment le Menu qui a lui tout seul possède autant de propriétés que tous les autres réunis et qui de plus peut être généré à partir de l'un des providers de navigation déclarés dans le fichier web.config, chacun des providers implémentés exposant avec plus ou moins de succès l'ensemble des propriétés déclarées dans le skin object.
On peut définir les propriétés des skin objects directement dans leur balise de contrôle au sein de l'ascx. Visual Studio fournit l'intellisense pour y accéder.
Tous les fichiers de ressource associés au skin (images, javascript, flash, css) sont sensés être positionnés dans le répertoire du thème ou dans des sous-répertoires , sachant qu'une feuille de style skin.css est attendue à la racine du thème et déclarée automatiquement, et qu'il est également possible de fournir sans la déclarer une css additionnelle du nom de fichier de l'ascx.
Ces ressources doivent être déclarées dans le html en chemin relatif par rapport à la racine de l'application, qui n'est pas le répertoire de l'ascx du thème. Il existe une fonction dans la classe Skin qui permet via un tag server d'obtenir ce chemin: SkinPath, ce qui donne par exemple:
<script language="javascript" type="text/javascript" src="<%= SkinPath %>js/unscript.js"></script>
On peut dans un même répertoire de skin fournir plusieurs ascx généralement, pour proposer plusieurs variantes de layout sur le même thème. On peut également associer à chaque ascx un jpeg du même nom, issu d'un screenshot, qui servira d'aperçu dans le module des gestion des skins.
Enfin il est possible de packager pour déploiement une skin et zippant le contenu de son répertoire et en donnant le nom du thème au zip; ce sera le nom donné au répertoire dans lequel seront dézippés les fichiers.
Le concept de skin est étendu à celui de container qui définit le gabarit d'enrobage des modules, on retrouve des skin objects de modules et tout ce qui est vrai pour les skins est à peu près vrai pour les containers, en remplaçant "Skins" par "Containers" pour les répertoires.
Il est également possible de packager skins et containers dans un même zip, dans ce cas dnn attend un zip au nom de la skin qui contient un zip "Containers.zip" et un zip "Skins.zip", chacun contenant les fichiers correspondant auparavant au zip principal du skin seul ou du container seul.
Voilà en gros ce qu'il suffit de connaître pour concevoir un thème graphique en ascx.
Maintenant, il se trouve que dans le but de faciliter le travail de graphistes non connaisseurs de l'ASP.Net, un petit moteur a été conçu pour automatiser et abstraire toutes les opérations qui nécessitent une telle connaissance, de telle sorte qu'un designer puisse fournir uniquement des fichiers Html au lieu des ascx, au prix d'un fichier XML de paramétrage additionnel, Skin.Xml.
Concrêtement, ce moteur parcours les fichiers Html du répertoire d'une skin, et pour chacun d'eux crée l'ascx correspondant, qui au html initial ajoute spécifiquement la déclaration du contrôle, celle des skin objects utilisés et leur positionnement, et la mise à jour des chemins des ressources à l'aide du tag server de chemin relatif si nécessaire.
Le moteur s'appuie sur le fait que les skin objects peuvent être déclarés dans le portail DotNetNuke dans le menu des définitions de modules à la première ligne d'un hypothétique module appelé [SkinObjects] et y sont associés comme des contrôles de formulaires de ce module avec pour clé un "token" de type [NOMDUSKINOBJECT]. Il ne s'agit pas vraiment d'un module, mais simplement d'une utilisation détournée du composant de gestion des modules, afin d'associer à chaque ascx d'un skin object un TOKEN qui pourra être utilisé pour le déclarer dans le html.
Le fichier Html peut contenir un header, et la déclaration de l'inclusion de la css skin.css, pour plus de confort lors du design en WYSIWYG (par exemple dans dreamweaver), sachant que seul le "body"' sera conservé à la génération et la css skin.css déclarée automatiquement.
Le graphiste place donc les skin objects en positionnant les tokens correspondants, et le fichier XML skin.xml sert à associer à chaque token de skin object les propriétés du contrôle qui seront placées à la génération directement dans la balise correspondante de l'ascx.
Il est possible d'utiliser plusieurs fois un skin object en lui associant un numéro [MENU:1] par exemple, qui devra être repris dans le XML de déclaration des propriétés.
Les panneaux - qui pour rappel sont dans l'ascx identifiés comme tous les controles de type <p>, <div>, <span>, <td> déclarés avec un runat="server" et un id="xx" qui donnera le nom au panneau dans dnn- peuvent être au choix déclarés de la même façon dans le html ou bien encore par un token [CONTENTPANE], qui sera unique dans un container, et dont on positionnera des instances énumérées dans le html d'un skin. Un div viendra positionner le panneau à la génération.
Il est également possible de préciser pour un panneau de skin le container spécifique qui doit être appliqué sur l'ensemble des modules du panneau en remplacement du container par défaut de la page, via une propriété déclarées dans le XML.
La skin doit être zippée comme précédemment pour pouvoir être déployée. Les fichiers html seront conservés lors du déploiement et pourront être édités à chaud puisque les ascx seuls sont utilisés à l'affichage.
La génération s'effectue une fois à l'installation d'un thème, ou encore par la suite sur commande manuelle depuis le menu de gestion des thèmes ("parse" ou "analyser" en français, pas très bien traduit à mon avis). On dispose alors d'une option permettant de déterminer si les chemins relatifs des ressources depuis la racine de l'application doivent être écrits en durs (donc plus rapide à l'exécution), ou conservés portables dans les ascx par l'utilisation de la méthode SkinPath.
Ce bouton, généralement peu connu, incite bon nombre de développeurs à négliger le mode de conception par html jugé moins immédiat à cause du packaging. Mais vous vous rendrez compte qu'il suffit d'une fenêtre prête à "parser" de nouveau le html à la moindre modification pour pouvoir éditer un thème à chaud et optimiser la vitesse de développement.
Enfin il existe depuis peu un module additionnel dans la page de gestion des skins permettant d'accèder dynamiquement aux tokens d'un thème ou d'un container pour en modifier les propriétés (dans le xml puis dans l'ascx). Il est alors possible d'en obtenir la description, si le développeur de skin object a renseigné un fichier XML décrivant les propriétés de son contrôle.