March Madness swept over the nation a few weeks ago, and I am lucky enough
to live in the hometown of one of the competitors for the NCAA champion-
ship. Naturally, I wanted to support the home team, so I whipped up some
images to replace my standard "welcome page" fare... including a slightly
revised logo. Of course, doing so was a bit of a PITA.
I'd considered creating some seasonal variations in image content and logo -
maybe featuring art or photography that celebrates each of the seasons or
something; logo changes for big football games and the holidays and the
like. But doing all this "manually" currently requires the content be
exchanged and the site be recompiled. Not so enticing, actually.
Then along came the idea to let the site do the work of managing special
event content automatically. All I'd need to do is create and upload the
content, plus devise a mechanism to make it all appear automagically....
of course!!
I'm going to assume that creation of the content -- that is, the idea that
the content I'm going to display must first be created -- is obvious. So
this is really all about the code and the XML that create the magical
mechanism.
In the broad strokes, the mechanism works by reading in the data, comparing
the current date with the start and end dates of each event, and, if
applicable, building a CSS file responsible for swapping the left side
images, and modifying attributes of certain HTML controls to make them
point to the new CSS and/or the special logo image.
The XML
========
My schema takes this shape:
For each event, we need a filename, a date range, and as many as three
paths: one for a logo change and two for the images used currently
along the left side -- one for the main image (goes on top), and one
for the repeated part below.
The Code
========
The code does four things each time a session is created:
o Read the XML into a dataset object (and filter it into a dataview)
o Compare the and data of each record from
the dataview with the current date to determine whether a special
event is currently underway
o If an event is underway, build fresh CSS file containing the path
information of any applicable images
o Point a placeholder HtmlLink object to the path for the new CSS
and modify the src attribute of the tag to point to the
revised logo
Because I'm having the code do this ONLY on the first web form a visitor
sees, all of the code to run this located in the local class.
First things first: We assign a dataset to hold our data, then create
an XmlTextReader object is instantiated to read the data into the ds.
I've probably described this several times in different how-to articles.
So I'll skip it for this one. I can always step you through it.
Next, call the AssembleSpecialEventStyle() subroutine from the Page_Load
event. The sub does exactly what it says:
If Not dsSpecialEvents Is Nothing AndAlso dsSpecialEvents.Tables.Count > 0 Then
Try
strToday = Date.Today
'create a dataview from the dataset
Dim dvDataView As New DataView(dsSpecialEvents.Tables(0))
from here, a rowfilter is created and the data is sorted. At least, that's
what should be happening. In truth, I'm having some trouble getting it to
work filtering dates. Seems that the RowFilter is better suited to doing
string comparisons. So I'll have to figure something else out there....
but the data is being sorted:
'sort on date (most recent at top)
.Sort = "dateEnd DESC"
Next up: Looping.
If dvDataView.Count > 0 Then
intUpperBound = dvDataView.Count - 1
For intCount = 0 To intUpperBound
'assign dataview columns to local variables
. . .
'perform date comparisons.
'- the end date must be AFTER the current date
'- the beginning date must be ON or BEFORE the current date
If (DateDiff(DateInterval.Day, CDate(strCurrentDateStart), CDate(strToday)) >= 0) And (DateDiff(DateInterval.Day, CDate(strToday), CDate(strCurrentDateEnd)) > 0) Then
'detect what's present in the dataset.
If Len(strCurrentPathImageLogo) > 5 Then blnHasLogoImage = True
If (Len(strCurrentPathImageTopBackground) > 5) And (Len(strCurrentPathImageBottomBackground) > 5) Then blnHasTopAndBottom = True
Okay. Here's where I use a filestream object to build the .css file.
'we're in the zone for a special event. Build the CSS.
If Len(strCurrentFilename) > 0 Then
Dim objSW As StreamWriter
Dim objFS As FileStream
Dim linkCSS As HtmlControls.HtmlLink
This HtmlLink points to a I planted on the master page.
Dim imgHeader As HtmlControls.HtmlImage
This image is my logo image, also planted on the master page.
Dim strCssFilePath As String = String.Empty
This will be the full .MapPath
strCurrentFilename = Trim(strCurrentFilename) & ".css"
strCssFilePath = Server.MapPath(strCssPath & strCurrentFilename)
Now, I want to make sure I have the latest data for this event. I'll do
that by deleting whatever .css is already present with this event name
and create a new one. So, out with the old...
If blnHasTopAndBottom Then
'if this .css file already exists, delete it
If IO.File.Exists(strCssFilePath) Then
File.Delete(strCssFilePath)
End If
... and in with the new:
objFS = New FileStream(strCssFilePath, FileMode.Create, FileAccess.ReadWrite)
objSW = New StreamWriter(objFS)
With the streamwriter object open, it's just like Response.Write in VBSCript.
You just... write stuff. Just remember to FLUSH the object BEFORE closing it.
With objSW
.Write(Chr(13))
.Write("#divImageInner {" & Chr(13))
.Write(" background-image:url(" & strCurrentPathImageTopBackground & ");" & Chr(13))
.Write("}" & Chr(13))
.Write(Chr(13))
.Write("#divImageOuter {" & Chr(13))
.Write(" background-image:url(" & strCurrentPathImageBottomBackground & ");" & Chr(13))
.Write("}" & Chr(13))
.Write(Chr(13))
.Write("/*Generated " & Now.ToShortDateString() & ". Valid from " & strCurrentDateStart & " until " & strCurrentDateEnd & " */" & Chr(13))
.Flush()
.Close()
End With
objFS.Close()
And that's it. Your new .css is written!
Next, we need to send the path of the new .css to the :
'point the special link to the path of the new file
linkCSS = Me.Master.FindControl("linkStyleSpecialEvent")
With linkCSS
.Href = strCssPath & strCurrentFilename
.Visible = True
End With
'tidy up
objSW = Nothing
objFS = Nothing
End If 'blnHasTopAndBottom = True
If blnHasLogoImage Then
'now point the header image to the path of the new file
imgHeader = Me.Master.FindControl("imgLogoHeader")
imgHeader.Src = strCurrentPathImageLogo
End If 'blnHasLogoImage
End If 'Len(strCurrentFilename) > 0
'bail
Exit For
That's the majority of the substance. Below this point, we have the
companion Else condition to the If in which a date comparison is formed.
We're going to use the opportunity to whack any special event .css files
to keep things tidy.
Else
'erase any files in the special event subdirectory
strOldFile = IO.Directory.GetFiles(Server.MapPath(strCssPath))
Dim intCnt As Int32
For intCnt = 0 To strOldFile.Length
IO.File.Delete(strOldFile(intCount))
Next
Erase strOldFile
End If '(intToday <= intCurrentDateStart) And (intToday >= intCurrentDateEnd)
Next 'For intCount = 0 To intUpperBound
And I'll do the same thing here -- under the Else to the original If.
Else 'dvDataView.Count > 0
'erase any files in the specialevent subdirectory
. . . (same code as above)
End If 'dvDataView.Count > 0
Catch ex As Exception
End Try '(Try)
End If 'Not dsSpecialEvents Is Nothing AndAlso dsSpecialEvents.Tables.Count > 0
That should be it for now! Contact me using the site's contact form if
you have questions. Feel free to use the code in your projects. A shout
out in your project would be thoughtful. Also, drop me a line and let me
know how you might have tweaked things to better suit your needs.
Finally, I wouldn't profess to be THE expert on matters represented in
my code -- so drop me a line if you have constructive suggestions, too.
I'd like to hear from you!
Best,
halfgk
copyright 2009 halfgk.com