| |
Write the Web™ 
The Web for You
February 14th, 2011
I’ve been using a linux-based Asus Eee PC (p701) for several years now, and one of my favorite features available is the desktop wallpaper “slideshow” option. I can set up my computer to randomly display a new desktop wallpaper as often as I want. All I have to do is point to the folder(s) the images are stored in and set the frequency, and viola my desktop wallpaper changes “automagically.”
I’ve almost given up on wallpapers for my home and office Windows machines, however. While it’s certainly not hard to change the desktop wallpaper, it’s not something I like to think about. To be honest, the desktop is always covered by the applications I’m working in, so I rarely even think about it. But a few months ago, I stumbled across the Microsoft Digital Photography Winter Fun Pack 2003. While most of the features are uninteresting to me, one of them caught my eye. The Winter Wallpaper Changer feature automatically changes your desktop wallpaper anywhere from once every 15 minutes to once a week. You can point the program to whatever folder you want that contains the background images. Even better, you can set it up so that on certain days (someone’s birthday, a holiday, or whatever), you can choose from a different set of wallpaper images!
I installed this application, and was immediately thrilled with how it worked. I like my wallpaper to change very frequently, so I had my wallpaper changed every fifteen minutes throughout the day. I never knew how easy it would be to brighten up my day just by changing my computer’s wallpaper!
Over the course of the next week, however, my enthusiasm for the application began to fade. I quickly realized that every morning when I logged in to my computer, the wallpaper slideshow started back at the beginning (the first image in my wallpapers folder). Since I rarely see my desktop wallpaper except when I log in or out, this meant that I kept seeing the same image every morning. This sort of defeats the purpose of changing the wallpaper (especially since the first image in my folder was one of my least favorite). I also noticed that every morning when I logged in to my computer, the program didn’t just start up in the background as I would have expected. Instead, I had to wait while Windows launched the installer program and re-installed (or possibly reconfigured?) the wallpaper changer. When it finished, instead of just running the program in the background, it opened up the user configuration dialog window. So I had to close that down before I could get to work for the day. Not a big deal, but a bit of a nuisance.
To make matters worse, I also realized that, even though I was very excited about the ability to override the wallpaper images on specific days, I was a bit disappointed in this feature overall. It worked exactly as advertised, and I quickly selected pictures to use on Christmas, Halloween, my kids’ birthdays, etc. But then I wondered what I would do for Thanksgiving. Since it doesn’t fall on the same day every year, I realized I could not have a specific set of wallpapers for that holiday. I also realized that I don’t always just want a particular wallpaper on a particular day. I thought it would be better to be able to have specific wallpapers for specific months. For October: Halloween pictures. For November: Fall pictures and Thanksgiving pictures. For December: Christmas pictures. For January: Winter pictures. You get the idea.
I quickly fell out of love with the Winter Wallpaper Changer from Microsoft. But I had become quite enamored with the idea of having my desktop wallpaper rotate automatically on a regular basis. So I decided I’d just go ahead and write my own desktop wallpaper changing script so I could build it the way I wanted it.
Below, I’ve included the source code for two VBS files (Visual Basic Scripts). These files can be edited with any text editor, but will run when double-clicked. Or, you can set them up as scheduled tasks (as I’ve done) so that they run automatically in the background on a pre-selected schedule.
NOTE: I was not able to find any way to automatically refresh the desktop to apply the new background images. Instead, this program will just select a random picture from your wallpapers folder, copy it to the “default” directory for your Windows desktop wallpaper, and update your registry settings to use the new file. You will probably not see a change until you log off the computer and log back on, or until Windows automatically refreshes the desktop (I think it does this about once every four hours).
Try it yourself:
For anyone who is interested, I’ve included the full code for both the WallpaperChanger.vbs and WallpaperChanger_Config.vbs files below. You can copy and paste the codes below into a text editor and save them to your computer (they must be in the same folder to work together). Of, if you prefer, you can download the zipped folder containing the two script files. Extract the contents to the same folder and they should work as-is.
Don’t forget to create a scheduled task to run the Wallpaperchanger.vbs script on a regular basis (I recommend only once at every login).
| WallpaperChanger.vbs |
| Notes: This script, when run, will check for a text file called “WallpaperChanger Settings.txt” that holds the configuration settings it uses. If the text file is not found, it will call the WallpaperChanger_Config.vbs script (see code below) to configure and install the “WallpaperChanger Settings.txt” |
Option Explicit
Dim _
colFolders, _
colSubfolders, _
configcontents(), _
configexists, _
configfilepath, _
configposition, _
configslideshow, _
da, _
defFile, _
edate, _
expLines, _
extName, _
file, _
folderPath, _
ForAppending, _
ForReading, _
ForWriting, _
foundlines, _
FSO, _
i, _
logcontents, _
logDirectory, _
logexists, _
logFile, _
logText, _
max, _
min, _
mo, _
moday, _
MyFiles, _
MyFolder, _
objFile, _
objFolder, _
objFSO, _
objLogFile, _
objNet, _
objReadFile, _
objShell, _
objStream, _
objSubfolder, _
objWallFile, _
objWMIService, _
ofolder, _
oSHApp, _
scriptPath, _
sdate, _
selectedwallpaper, _
SlideShow, _
SlideFolder, _
SPath, _
strComputer, _
strDesktop, _
subFolder, _
sUserName, _
sWallPaper, _
sWinDir, _
SysFolder, _
temp, _
therand, _
userreply, _
varPathCurrent, _
wallDirectory, _
wallFile, _
wallText
Set FSO = CreateObject("Scripting.FileSystemObject")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objNet = CreateObject("WScript.Network")
Set objShell = CreateObject("WScript.Shell")
Set oSHApp = CreateObject("Shell.Application")
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
ForAppending = 8
ForReading = 1
ForWriting = 2
SPath = "C:\Documents and Settings\" & objNet.UserName _
& "\Local Settings\Application Data\Microsoft"
scriptPath = Left(WScript.ScriptFullName, InstrRev(WScript.ScriptFullName, _
WScript.ScriptName) -1)
wallDirectory = scriptPath
wallFile = "WallpaperChanger Settings.txt"
mo = Month(Now())
da = Day(Now())
if (mo<10) then
mo = "0" & mo
else
mo = "" & mo
end if
if (da<10) then
da = "0" & da
else
da = "" & da
end if
On Error Resume Next
Err.Clear
GetSetConfigFile()
VerifyConfigSettingsFileLines
if (explines = foundlines) then
ReadWallFile
else
WScript.Echo "An error has occured with the configuration file: " _
& vbNewLine & wallDirectory & wallFile & vbNewLine _
& "Executing built-in pause for 5 seconds to rebuild file."
WScript.Sleep(2500)
ModifyConfigurationSettingsfile
end if
SelectNewWallpaper
SetUserWallpaper
WScript.Quit
Function GetSetConfigFile ()
On Error Resume Next
Err.Clear
if objFSO.FolderExists(wallDirectory) then
Set objFolder = objFSO.GetFolder(wallDirectory)
else
Set objFolder = objFSO.CreateFolder(wallDirectory)
end if
if NOT(objFSO.FileExists(wallDirectory & wallFile)) then
CreateConfigurationSettingsFile
end if
Set objFile = Nothing
Set objFolder = Nothing
End Function
Function VerifyConfigSettingsFileLines ()
On Error Resume Next
Err.Clear
foundlines = 0
explines = 14
Set objWallFile = objFSO.OpenTextFile (wallDirectory _
& wallFile, ForReading)
i = 0
Do Until objWallFile.AtEndOfStream
temp = objWallFile.ReadLine
i=i+1
Loop
objWallFile.close
set objWallFile = Nothing
foundlines = i
End Function
Function ReadWallFile ()
On Error Resume Next
Err.Clear
Set objWallFile = objFSO.OpenTextFile (wallDirectory & wallFile, ForReading)
i=0
Do Until objWallFile.AtEndOfStream
Redim Preserve configcontents(i)
configcontents(i) = objWallFile.ReadLine
i=i+1
Loop
objWallFile.close
Set objWallFile = Nothing
if (configcontents(1) > "" AND configcontents(7) > "" _
AND configcontents(10) > "") then
configfilepath = configcontents(1)
configposition = configcontents(7)
configslideshow = configcontents(10)
' If file exists, passes verification, and contains acceptable entries,
' let the program know it exists.
configexists = true
else
configexists = false
end if
End Function
Function CreateConfigurationSettingsFile()
On Error Resume Next
Err.Clear
Set objWallFile = objFSO.CreateTextFile (wallDirectory & wallFile, ForWriting)
objWallFile.WriteLine("Wallpaper Directory:")
objWallFile.WriteLine("C:\Documents and Settings\" & objNet.UserName _
& "\My Documents\My Pictures")
objWallFile.WriteLine("")
objWallFile.WriteLine("Current Wallpaper:")
objWallFile.WriteLine("")
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Position:")
objWallFile.WriteLine("2")
objWallFile.WriteLine("")
objWallFile.WriteLine("Include My Pictures Slideshow?")
objWallFile.WriteLine("No")
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Last Changed:")
objWallFile.WriteLine("")
ModifyConfigurationSettingsFile
End Function
Function ModifyConfigurationSettingsFile()
On Error Resume Next
Err.Clear
temp = """" & scriptPath & "\WallpaperChanger_Config.vbs"""
objShell.Run(temp)
End Function
Function SelectNewWallpaper()
On Error Resume Next
Err.Clear
if (configexists = true) then
If objFSO.FolderExists(configfilepath) then
Set SysFolder = FSO.GetFolder(configfilepath)
else
userreply = msgbox("Unable to find the selected wallpaper directory. " _
& "Would you like to change your wallpaper changer " _
& "settings now?", vbYesNo)
if (userreply = 6) then
ModifyConfigurationSettingsFile
end if
WScript.Quit
end if
Set MyFolder = FSO.GetFolder(configfilepath)
folderPath = configfilepath
Set MyFolder = FSO.GetFolder(configfilepath)
folderPath = configfilepath
if (objFSO.FolderExists(configfilepath & "\" & mo)) then
Set temp = FSO.GetFolder(configfilepath & "\" & mo)
if (temp.Files.Count > 0) then
Set MyFolder = FSO.GetFolder(configfilepath & "\" & mo)
folderPath = configfilepath & "\" & mo
moday = mo
end if
end if
Set objFolder = objFSO.GetFolder(configfilepath)
Set colSubfolders = objFolder.Subfolders
For Each objSubfolder in colSubfolders
if (instr(1,objSubfolder.Name,"-") > 0) then
sdate = left(objSubfolder.Name, instr(1, _
objSubfolder.Name,"-")-1)
edate = right(objSubfolder.Name, InstrRev(_
objSubfolder.Name, "-")-1)
if ((mo & "_" & da) >= sdate _
AND (mo & "_" & da) <= edate) then
Set temp = FSO.GetFolder(configcontents(1) _
& "\" & objSubfolder.Name)
if (temp.Files.Count > 0) then
Set MyFolder = FSO.GetFolder(configcontents(1) _
& "\" & objSubfolder.Name)
folderPath = configcontents(1) & "\" _
& objSubfolder.Name
moday = objSubfolder.Name
end if
end if
end if
Next
(objFSO.FolderExists(configfilepath & "\" & mo & "_" & da)) then
Set temp = FSO.GetFolder(configfilepath & "\" & mo _
& "_" & da)
if (temp.Files.Count > 0) then
Set MyFolder = FSO.GetFolder(configfilepath & "\" & mo _
& "_" & da)
folderPath = configcontents(1) & "\" & mo & "_" & da
moday = mo & "_" & da
end if
end if
max = MyFolder.Files.Count
min = 1
Randomize
therand = Int((max-min+1) * Rnd+min)
temp = ""
i = 0
For each file in MyFolder.Files
i = i+1
extName = right(file.Name, 3)
if (extName="jpg" OR extName="JPG" OR extName="bmp" _
OR extName="BMP" OR extName="gif" _
OR extName="GIF") then
if (temp="") then
temp = file.Name
defFile = file.Name
end if
if (i=therand) then
temp = file.Name
end if
else
if (i=therand) then
min=i+1
Randomize
therand = Int((max-min+1)*Rnd+min)
end if
end if
Next
if (temp="") then
selectedwallpaper = defFile
else
selectedwallpaper = temp
end if
else
WScript.Quit
end if
End Function
Function SetUserWallpaper()
On Error Resume Next
Err.Clear
if (isnull(selectedwallpaper) OR selectedwallpaper = "") then
msgbox("No wallpaper found in " & folderPath & "\" _
& selectedwallpaper)
else
if objFSO.FileExists(SysFolder & "\Wallpaper1.bmp") then
objFSO.DeleteFile SysFolder & "\Wallpaper1.bmp"
end if
if objFSO.FileExists(SysFolder & "\Wallpaper1.jpg") then
objFSO.DeleteFile SysFolder & "\Wallpaper1.jpg"
end if
if objFSO.FileExists(SysFolder & "\Wallpaper1.gif") then
objFSO.DeleteFile SysFolder & "\Wallpaper1.gif"
end if
objFSO.CopyFile folderPath & "\" & selectedwallpaper , SPath _
& "\" & "Wallpaper1." & right(selectedwallpaper, 3)
Set objWallFile = objFSO.CreateTextFile (wallDirectory _
& wallFile, ForWriting)
objWallFile.WriteLine("Wallpaper Directory:")
objWallFile.WriteLine(configfilepath)
objWallFile.WriteLine("")
objWallFile.WriteLine("Current Wallpaper:")
if (configfilepath = folderPath) then
objWallFile.WriteLine(selectedwallpaper)
else
objWallFile.WriteLine(moday & "\" & selectedwallpaper)
end if
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Position:")
objWallFile.WriteLine(configposition)
objWallFile.WriteLine("")
objWallFile.WriteLine("Include 'My Pictures Slideshow?'")
objWallFile.WriteLine(configslideshow)
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Last Changed:")
objWallFile.WriteLine(Now())
objWallFile.close
Set objWallFile = Nothing
sWallPaper = SPath & "\" & "Wallpaper1." & right(temp, 3)
objShell.RegWrite "HKCU\Control Panel\Desktop\Wallpaper", _
sWallPaper
if (configposition=1) then
objShell.RegWrite "HKCU\Control Panel\Desktop\TileWallpaper", 1
else
objShell.RegWrite "HKCU\Control Panel\Desktop\TileWallpaper", 0
end if
if (wallPosition > -1 AND wallPosition < 3) then
objShell.RegWrite "HKCU\Control Panel\Desktop\WallpaperStyle", _
configposition
else
objShell.RegWrite "HKCU\Control Panel\Desktop\WallpaperStyle", 2
end if
if (configslideshow="Yes") then
objShell.RegWrite "HKEY_CURRENT_USER\Control Panel\" _
& "Screen Saver.Slideshow\ImageDirectory", FolderPath
end if
objShell.Run "%windir%\System32\RUNDLL32.EXE " _
& "user32.dll,UpdatePerUserSystemParameters", 1,True
end if
End Function
|
| WallpaperChanger_Config.vbs |
| Notes: This script, when run, will create or update a text file called “WallpaperChanger Settings.txt” that holds the configuration settings used by “WallpaperChanger.vbs.” The user settings control which directory holds the wallpaper, which image folder to use, and whether or not the same directory should be used for the Windows Slideshow screensaver. |
Option Explicit
Dim _
configcontents(), _
configexists, _
configfilepath, _
configimage, _
configposition, _
configslideshow, _
currentImage, _
defFile, _
explines, _
extName, _
file, _
ForAppending, _
ForReading, _
ForWriting, _
foundlines, _
FSO, _
i, _
logcontents, _
logDirectory, _
logexists, _
logFile, _
logText, _
MyFolder, _
MyFiles, _
objFile, _
objFolder, _
objFSO, _
objLogFile, _
objNet, _
objReadFile, _
objShell, _
objStream, _
objWallFile, _
ofolder, _
oldFilePath, _
oSHApp, _
scriptPath, _
SPath, _
strComputer, _
strDesktop, _
sUserName, _
sWinDir, _
sWallPaper, _
SysFolder, _
temp, _
uinput, _
userPath, _
userFile, _
wallDirectory, _
wallFile, _
wallText
Set FSO = CreateObject("Scripting.FileSystemObject")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objNet = CreateObject("WScript.Network")
Set objShell = CreateObject("WScript.Shell")
Set oSHApp = CreateObject("Shell.Application")
ForAppending = 8
ForReading = 1
ForWriting = 2
scriptPath = Left(WScript.ScriptFullName, _
InstrRev(WScript.ScriptFullName, _
WScript.ScriptName) -1)
wallDirectory = scriptPath
wallFile = "WallpaperChanger Settings.txt"
GetSetConfigFile()
VerifyConfigSettingsFileLines
if (explines <> foundlines) then
WScript.Echo "An error has occured with the" _
& "configuration file: " & vbNewLine & wallDirectory _
& wallFile & vbNewLine & "Executing built-in" _
& " pause for 5 seconds to rebuild file."
WScript.Sleep(2500)
CreateConfigurationSettingsFile
end if
if (explines = foundlines) then
ReadWallFile
else
WScript.Quit
end if
GetUserInput
temp = """" & scriptPath & "\WallpaperChanger.vbs"""
objShell.Run(temp)
objWallFile.close
Set objWallFile = Nothing
Set objFSO = Nothing
Set objNet = Nothing
Set objShell = Nothing
Set oSHApp = Nothing
WScript.Quit
Function GetSetConfigFile ()
On Error Resume Next
Err.Clear
if objFSO.FolderExists(wallDirectory) then
Set objFolder = objFSO.GetFolder(wallDirectory)
else
Set objFolder = objFSO.CreateFolder(wallDirectory)
' WScript.Echo "Successfully installed" _
' & " configuration directory: " _
' & wallDirectory
end if
if NOT(objFSO.FileExists(wallDirectory & wallFile)) then
CreateConfigurationSettingsFile
end if
objWallFile.close
Set objWallFile = Nothing
Set objFile = Nothing
Set objFolder = Nothing
End Function
Function VerifyConfigSettingsFileLines ()
On Error Resume Next
Err.Clear
foundlines = 0
explines = 14
Set objWallFile = objFSO.OpenTextFile (wallDirectory _
& wallFile, ForReading)
i = 0
Do Until objWallFile.AtEndOfStream
temp = objWallFile.ReadLine
i=i+1
Loop
objWallFile.close
Set objWallFile = Nothing
foundlines = i
End Function
Function ReadWallFile ()
On Error Resume Next
Err.Clear
Set objWallFile = objFSO.OpenTextFile (wallDirectory & wallFile, ForReading)
i=0
Do Until objWallFile.AtEndOfStream
Redim Preserve configcontents(i)
configcontents(i) = objWallFile.ReadLine
i=i+1
Loop
objWallFile.close
Set objWallFile = Nothing
if (configcontents(1) > "" _
AND configcontents(7) > "" AND configcontents(10) > "") then
configfilepath = configcontents(1)
configposition = configcontents(7)
configslideshow = configcontents(10)
configimage = configcontents(3)
configexists = true
else
configexists = false
end if
End Function
Function CreateConfigurationSettingsFile()
On Error Resume Next
Err.Clear
Set objWallFile = objFSO.CreateTextFile (wallDirectory & wallFile, ForWriting)
objWallFile.WriteLine("Wallpaper Directory:")
objWallFile.WriteLine("C:\Documents and Settings\" & objNet.UserName _
& "\My Documents\My Pictures")
objWallFile.WriteLine("")
objWallFile.WriteLine("Current Wallpaper:")
objWallFile.WriteLine("")
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Position:")
objWallFile.WriteLine("2")
objWallFile.WriteLine("")
objWallFile.WriteLine("Include My Pictures Slideshow?")
objWallFile.WriteLine("No")
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Last Changed:")
objWallFile.WriteLine("Never")
objWallFile.close
Set objWallFile = Nothing
WScript.Sleep 10000
GetSetConfigFile
VerifyConfigSettingsFileLines
End Function
Function GetUserInput()
Dim objIE
Set objIE = CreateObject( "InternetExplorer.Application" )
objIE.Navigate "about:blank"
objIE.Document.Title = "Wallpaper Changer Configuration"
objIE.ToolBar = False
objIE.Resizable = True
objIE.StatusBar = False
objIE.Width = 700
objIE.Height = 500
With objIE.Document.ParentWindow.Screen
objIE.Left = (.AvailWidth - objIE.Width ) \ 2
objIE.Top = (.Availheight - objIE.Height) \ 2
End With
dim ttov1, ttov2, ttov3
ttov1 = ""
ttov2 = ""
ttov3 = ""
if (configposition = "0") then
ttov1 = " selected"
end if
if (configposition = "1") then
ttov2 = " selected"
end if
if (configposition = "2") then
ttov3 = " selected"
end if
dim ss
ss = ""
if (configslideshow = "Yes") then
ss = " selected"
end if
Do While objIE.Busy
WScript.Sleep 200
Loop
objIE.Document.Body.InnerHTML = "<div align=""left""><h4>Custom Wallpaper " _
& "Configuration Settings:</h4>" & vbCrLf _
& "<p><b>Enter the path to your wallpapers folder: </b><br/><input " _
& "type=""text"" size=""20"" " _
& "id=""UserPath"" value=""" & configfilepath & """></p>" & vbCrLf _
& "<p><b>Select how you want your wallpaper to appear: " _
& "</b><br/>" _
& "<select id=""TileType"" value=""" & configposition & """>" & vbCrLf _
& " <option value=""0""" & ttov1 & ">Center</option>" & vbCrLf _
& " <option value=""1""" & ttov2 & ">Tile</option>" _
& vbCrLf & " <option value=""2""" & ttov3 _
& ">Stretch</option>" & vbCrLf _
& "</select>" & vbCrLf _
& "<p><b>Use the same directory for the ""My Pictures Slideshow"" " _
& "screensaver?</b><br/>" & vbCrLf _
& "<select id=""Slideshow"" value=""" & configslideshow _
& """>" & vbCrLf _
& " <option value=""No"">No</option>" & vbCrLf _
& " <option value=""Yes""" & ss & ">Yes</option" & vbCrLf _
& "</select></p>" & vbCrLf _
& "<p><input type=""hidden"" id=""OK"" " _
& "name=""OK"" value=""0""><br/>" _
& "<input type=""submit"" value="" OK "" " _
& "OnClick=""VBScript:OK.Value=1""></p></div>"
objIE.Document.Body.Style.overflow = "auto"
objIE.Visible = True
objIE.Document.All.UserPath.Focus
On Error Resume Next
Do While objIE.Document.All.OK.Value = 0
WScript.Sleep 200
If Err Then
IELogin = Array( "", "" )
objIE.Quit
Set objIE = Nothing
Exit Function
End if
Loop
On Error Goto 0
Set objWallFile = objFSO.CreateTextFile (wallDirectory & wallFile, True)
objWallFile.WriteLine("Wallpaper Directory:")
objWallFile.WriteLine(objIE.Document.All.UserPath.Value)
objWallFile.WriteLine("")
objWallFile.WriteLine("Current Wallpaper:")
objWallFile.WriteLine(configcontents(4))
objWallFile.WriteLine("")
objWallFile.WriteLine("Wallpaper Position:")
objWallFile.WriteLine(objIE.Document.All.TileType.Value)
objWallFile.WriteLine("")
objWallFile.WriteLine("Include 'My Pictures Slideshow?'")
objWallFile.WriteLine(objIE.Document.All.Slideshow.Value)
objWallFile.WriteLine("")
objWallFile.WriteLine()
objWallFile.WriteLine(Now())
objIE.Quit
Set objIE = Nothing
MsgBox("Your settings have been saved!")
End Function
|
That’s all for today…now get out there and Write the Web!
Posted in Downloads, Level: Intermediate, Microsoft Windows, VBScript | No Comments »
October 29th, 2010
The problem
I’m learning how to build ASP.NET websites in C# using Microsoft Visual Studio 2005. Everything about this is new to me. I have done a lot of work building HTML websites, quite a bit of javascript, and a little php and MySQL development. But now everything I know amounts to nothing as I try to learn a new development environment (Visual Studio), and two new programming languages (C# and ASP.NET). It’s an interesting process, and I rather enjoy what I’m learning, but I wanted to make it clear right up front that the advice included in this post may not be the best advice you can find: I still have a lot to learn!
That being said, let me describe one of the first problems I encountered in my new programming scenario:
I am building a website to allow users to add, edit, and delete items in a list of events. I am using an ASP.NET/Visual Studio MultiView control to manage the process flow for selecting and editing the events. The first view that the user sees is a GridView control displaying the complete list of events in the database.
Image 1: The GridView control listing the events

From this GridView, the user will select an event to view or edit. When they select an event, they are taken to the next View in the MultiView control where they will see a DetailsView control with the specific details for that event.
Image 2: The DetailsView for a particular event

For my application, I needed to have a third View control with additional details. This was not a problem until I tried to add a new item to my database. As soon as I added the new item, I realized that the GridView control was either reset to select nothing or else it kept its original selection rather than automatically selecting the new item. What’s worse, since my GridView’s data source is sorted, the GridView would often have the same index (relative position) selected, but it could be a completely different item since the actual values at each index had changed!
To avoid this problem, I needed to find some way for the application to insert a new item into my SQL database, return the Identity (ID) value for that new record, refresh the data displayed in my GridView List, and then automatically select the row in my GridView list that contains the new record. Here’s how I did it:
Step 1: Returning the primary key (identity) of the new record
The most important piece of this, it seemed to me, was getting the web page to actually record the value of the new identity column. I am used to programming with PHP and MySQL, and there is a handy built-in function that allows you to do this easily. You simply call a MySQL INSERT operation and then call the function mysql_insert_id(), which returns the Identity (ID) of the record inserted. There is no such built-in function in SQL, ASP.NET, or Visual Studio. So I had to build my own method to do this.
First, I wrote a Stored Procedure in SQL Server Management Studio that would take the values from my website, insert them into a new record in the SQL database, and return the value of the Identity of the newly-inserted record. Here’s the stored procedure I used:
| SQL Code Sample: Stored Procedure that inserts a new record and returns the Identity value |
CREATE PROCEDURE [dbo].[spAddEventAndReturnEventIDValue] (
@startDate DateTime,
@endDate DateTime,
@title varchar(500),
@description varchar(1000),
@location varchar(500),
@NewID int = NULL OUTPUT
)
AS
BEGIN
INSERT INTO [tblCalendarEvent] ([startDate], [endDate], [title],
[description], [location])
VALUES (@startDate, @endDate, @title,
@description, @location)
SET @NewID = SCOPE_IDENTITY()
RETURN @NewID
END
|
Once you have created your stored procedure, it is a fairly simple matter to call it. In Visual Studio, select the SQL data source control and change the properties such that the InsertCommandType is “StoredProcedure” and in the InsertQuery Query Builder window (Where you would normally type the SQL INSERT query itself), type in the name of the stored procedure (In this case, spAddEventAndReturnEventIDValue).
Step 2: Finding and selecting the new record in your GridView control
Simply calling a stored procedure that returns a value is not enough to do the job, of course. The next thing you have to do is take that returned value and make it the selected value for the GridView control.
Used to dealing with DropDown lists, I thought I could just assign the GridView’s value property to the returned value using a statement something like this:
GridView1.SelectedValue = command.Parameters["@NewID"].Value;
Unfortunately, it is not that easy. When I tried to do this, I got the following error message:
Compiler Error Message: CS0200: Property or indexer ‘System.Web.UI.WebControls.GridView.SelectedValue’ cannot be assigned to — it is read only
So much for doing things the easy way. The only thing left to do, as far as I could figure, would be to write a code that cycles through the entire GridView list until it finds a row that matches the value returned by my stored procedure (The Identity value of the newly-inserted record). In my case, the GridView was set to allow paging, so I had to not only identify the correct index of the new record, but also the right page.
I don’t know if this is the best or the only way to do things, but here’s the code that I came up with:
| C# Code Sample: Forcing a GridView to select the ID of a record inserted by a bound DetailsView |
using System;
using System.Data.Common;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class PageName : System.Web.UI.Page
{
protected void On_Inserted(
object sender, SqlDataSourceStatusEventArgs e)
{
DbCommand command = e.Command;
String NewID =
command.Parameters["@NewID"].Value.ToString();
int sel = -1;
int pag = -1;
for (int i = 0; i < GridView1.PageCount; i++)
{
GridView1.PageIndex = i;
GridView1.DataBind();
int row = 0;
foreach (DataKey dk in GridView1.DataKeys )
{
if (dk.Value.ToString().ToLower() ==
NewID.ToLower()
)
{
sel = row;
pag = i;
}
row = row + 1;
}
}
SQLDataSource1.DataBind();
GridView1.DataBind();
GridView1.PageIndex = pag;
GridView1.SelectedIndex = sel;
DetailsView1.PageIndex = 0;
DetailsView1.ChangeMode(
DetailsViewMode.ReadOnly);
DetailsView1.DataBind();
}
}
|
The final piece that is required is to make sure that the function coded above actually runs when a new record is inserted. To do that, you’ll have to add some codes to your ASPX page manually. First, you need to find the SQL data source control that calls your stored procedure. It should look something like this:
<asp:SqlDataSource ID=”SQLDataSource1″ runat=”server” ConnectionString=”<%$ ConnectionStrings:ConnectionString1 %>” InsertCommand=”spAddEventAndReturnEventIDValue” InsertCommandType=”StoredProcedure” >
Just add the call to the new On_Inserted method by adding OnInserted=”On_Inserted” somewhere in the data source’s <asp:SqlDataSource> tag, and your application should work. The new code for SqlDataSource1 should look like this:
<asp:SqlDataSource ID=”SQLDataSource1″ runat=”server” ConnectionString=”<%$ ConnectionStrings:ConnectionString1 %>” InsertCommand=”spAddEventAndReturnEventIDValue” InsertCommandType=”StoredProcedure” OnInserted=”On_Inserted”>
Now, when you insert a new record via your DetailsView control, the new information will be stored in the SQL Server database, SQL Server will return the value of the Identity column for the new row, and your page will automatically set the GridView control to select the newly-inserted item. This is so much better than having to go back to the beginning, search for and select the record you just inserted, and page through the rest of the MultiView until you get to the section you need to work on!
That’s all for today…now get out there and Write the Web!
Posted in ASP.NET, C#, Visual Studio | No Comments »
July 19th, 2008
Listgarden is a very powerful RSS creation and management tool that runs on Windows, Mac, and Linux platforms, and can be configured as a Web-based application.
For those of you who subscribe to all of my feeds, let me apologize…I know that I’ve mentioned Listgarden several times: in this blog, the Lockworld Herald News, and my Resources feed.
I think the program deserves all of these mentions, however, because it is so versatile and so simple. Without any knowledge of RSS or XML structure or rules, you can create and edit as many feeds as you want to. You have the options of creating the feeds as local files on your computer, or uploaded to your FTP server (or both). My favorite feature of Listgarden is that you can optionally export an HTML version of your feed containing some or all of your feed items as a Web-based file. This can allow you to offer a preview of your latest feed items to your site visitors or an alternate way to view “what’s new” on your site.
The program uses a Web-based GUI, which makes it a little bit unusual to work with at first. But once you get the hang of things, you can be publishing RSS feeds in no time. The only downside is that there is no WYSIWYG (What You See is What You Get) editor, so if you want to include rich text, images, or links in your feed items, you will have to write the HTML codes for these items.
You can completely customize both your feed and your HTML output any way you want, which is very nice. For example, if you sell advertisements in your feed, or want to offer between-item ads from Google AdSense or other sources, you can easily modify your template to accommodate this. Furthermore, since you can completely customize your HTML output, you can ensure that your page is ready for viewing as soon as it’s exported, with any navigation structure, introductory text, links to the RSS feed for subscriptions, footers, etc.
I use Listgarden to create and manage my Lockworld Herald News feed. Because this feed is entirely self-promotional, I don’t expect many people to subscribe to it. However, for visitors to my site, glancing at the HTML version of the feed (the link above) will give them an overview about any recent changes I’ve made to the site, without having to subscribe to the RSS feed.
Of course, most modern Web browsers now have the capability to display RSS feeds in readable format, rather than the raw code they used to show. Furthermore, services like FeedBurner offer a Web-readable version of your feed automatically. So the HTML version is not essential. But the advantage is that it can contain all of your navigation structure so visitors can see what else you have to offer, and that it can be designed to match your site’s look and feel.
Listgarden can also be used as a PortableApp (run from a USB drive, rather than installed locally). You can even use multiple instances of Listgarden (not simultaneously) by installing them in different folders on your computer to manage different sets of feeds. This can be particularly useful for those who manage RSS feeds for other people’s sites, or for multiple sites of their own. Of course, with Listgarden you can have as many feeds as you want to in each application folder on your machine, if you only want to run one copy of the application.
Because it is available for Windows, Mac, and Linux and can be used portably, it is ideal for people working on the same projects on multiple platforms. For example, I use both a Linux-based Eee PC and a Windows XP PC to work on my site. Fortunately, I can manage my feeds on either computer (although I have to be using the right computer to actually publish the local file once I’ve made changes, because the file locations on the two machines are different).
I’ve tried using several different RSS feed creation tools in the past, but none have offered me the power and flexibility of Listgarden. So if the other methods I’ve used (here and here) don’t quite work for you, Listgarden might just be worth a try.
That’s all for today…now get out there and Write the Web!
Posted in Content Management, Level: Intermediate, Product/Service Review, RSS | No Comments »
|
|
|