Today, I was presented with an interesting problem. How can you use the same content for two different website, but account for some very minor changes in your DotNetNuke skin? After thinking about it for a little bit, I decided to override the base Skin class. Turns out, with an RESX or XML file, this is a pretty darn elegant solution.
First, let's take a look at the code. In order to do this properly, the class being created needs to inherit from DotNetNuke.UI.Skins.Skin. This enables the class to pick up all of the appropriately used public properties and methods and provides the ability to add overridden/custom properties. In my particular case, the driving force behind the customization in the skin development was the URL name. I probably could use any PortalSetting (name, ID, etc), but I chose to go with the URL. It's easy enough to get. Here's what my code started off looking like:
public
class
MySkinDefault : DotNetNuke.UI.Skins.Skin
{
public MySkinDefault()
{
}
}
At this point, the code is doing nothing. Loading a skin that inherits from this class will load exactly like the regular skin object. That's no fun. In the skin I was working with, I added three ASP.Net controls, a Label and two Literal controls. To make sure that my custom Skin class could reference them, I added three new lines of code.
public
class
MySkinDefault : DotNetNuke.UI.Skins.Skin
{
protected System.Web.UI.WebControls.Label lbl;
protected System.Web.UI.WebControls.Literal ltcTop;
protected System.Web.UI.WebControls.Literal ltcBottom;
public MySkinDefault()
{
}
}
The new items are scoped as protected so that they can interact with the ASCX file. This is important because if they are marked private, the code-behind file that gets generated by the .Net framework wil not be able to access the controls. For more info, check this link out: http://msdn.microsoft.com/en-us/library/015103yb(vs.71).aspx. It's a bit dated, but it helps explain.
Now that I have controls on my skin that I can reference, I need to be able to dynamically fill them. For that, I need to override the base class's OnLoad event.
protected override void OnLoad( EventArgs e )
{
if (!IsPostBack)
{
if (Context.Request.Url.Host == www.myexample.com)
{
lbl.Text = "I am at myexample.com!";
ltcTop.Text = "<a href=\"http://www.somewhereelse.com\">Some where else!</a>";
}
else
{
lbl.Text = "I am not at myexample.com!";
ltcTop.Text = "<a href=\"http://www.myexample.com\">myexample.com</a>";
}
ltcBottom.Text = ltcTop.Text;
}
base.OnLoad( e );
}
Two things to note:
- The override keyword let's me override the base implementation of the OnLoad event. Since it's overriding the event, I don't need to pass it a sender (that's already done for me in the initial declaration).
- I want DotNetNuke's base Skin object to pick up where my method completes, so I call my base class's OnLoad event, passing the e argument from my class. The reason I want DNN to finish it's work is because the Page_Load event does a bunch of more stuff, and I don't want it to code it in my implmentation.
My finished class looks like this:
public
class
MySkinDefault : DotNetNuke.UI.Skins.Skin
{
protected System.Web.UI.WebControls.Label lbl;
protected System.Web.UI.WebControls.Literal ltcTop;
protected System.Web.UI.WebControls.Literal ltcBottom;
public MySkinDefault()
{
}
protected override void OnLoad( EventArgs e )
{
if (!IsPostBack)
{
if (Context.Request.Url.Host == www.myexample.com)
{
lbl.Text = "I am at myexample.com!";
ltcTop.Text = "<a href=\"http://www.somewhereelse.com\">Some where else!</a>";
}
else
{
lbl.Text = "I am not at myexample.com!";
ltcTop.Text = "<a href=\"http://www.myexample.com\">myexample.com</a>";
}
ltcBottom.Text = ltcTop.Text;
}
base.OnLoad( e );
}
}
Pretty simple stuff. Now comes the fun part of making sure that my Skin uses this class. To do that, I need to make certain of two things:
- In the Page Declaration section, I need to inherit from this class, not the DotNetNuke Skin class.
- That my Label and my Literal controls are present on the skin. Since I'm not checking to see if those to control instances are null, they must be there. Otherwise I get a NullException.
Here's what my skin object would look like:
<%@
Control
Language="vb"
AutoEventWireup="false"
Explicit="True"
Inherits=" MySkinDefault"
%>
<table>
<tr>
<td><asp:Label id="lbl"
runat="server"
/></td>
<td style="text-align:right;"><asp:Literal ID="ltcTop"
runat="server"
/></td>
</tr>
<tr>
<td colspan="2" ID="ContentPane"
runat="server"></td>
</tr>
<tr>
<td colspan="2"
style="text-align:right;"><asp:Literal ID="ltcBottom"
runat="server" /></td>
</tr>
</table>
And there you have it! An overridden skin that you can customize even further than the what the out of the box DotNetNuke install provides.