Exploring the GrabAPicture Application (Part 8)

Last week, in the Exploring the GrabAPicture Application (Part 7) post, you discovered the Style and WallpaperURI properties of the WinWallpaper class. These complex properties are used to define two of three wallpaper entry values for each wallpaper used to decorate the Desktop. It may have surprised you to see how complex a task these settings are, but they require interaction with the Win32 API, among other APIs, in order to function properly. So far, you haven’t saved a single setting to disk though. This post takes things another step. We’ll discuss how to start working with settings within the application, which includes creating local and remote wallpaper lists.

Before you can do anything, you need to create another class named GrabAPictureSettings (contained in GrabAPictureSettings.vb). The Exploring the GrabAPicture Application (Part 5) post contains a set of steps you can use to create a new class. This new class contains everything needed to manage settings. It doesn’t actually perform any settings tasks, but it provides the resources to accomplish them.

The first step is to provide all of the Imports statements used for this class. In this case, the requirements are somewhat obvious. You’ll need resources to manage the XML files, serialize the data, and also perform I/O. Here are the three Imports you’ll need.

Imports System.Xml
Imports System.Xml.Serialization
Imports System.IO

The class also needs a number of private variables to manage the settings. As with all other private settings in this example, these settings use a leading underscore to show they’re private:

' Private local variables represent settings.
Private _LocalChecked As Boolean = False
Private _RemoteChecked As Boolean = False
Private _LocalUris() As LocalUri
Private _RemoteUris() As RemoteUri

The first two settings _LocalChecked and _RemoteChecked correspond to the Use Random Local Sources and Use Random Remote Sources checkboxes on the main GrabAPicture application dialog (see the Exploring the GrabAPicture Application (Part 1) and Exploring the GrabAPicture Application (Part 2) posts for details). These private variables make user changes to those checkboxes permanent. In addition, the state of these variables determines which sources the application uses to select wallpaper.

The second two settings, _LocalUris and _RemoteUris, are arrays of wallpaper entries. These arrays will ultimately provide the list of wallpaper entries that the application randomly chooses from to display on the Desktop. These arrays also provide the content for the Local Sources and Remote Sources lists in the Configure a Random Source dialog box (see the see the Exploring the GrabAPicture Application (Part 1) and Exploring the GrabAPicture Application (Part 3) posts for details).

These variables are private, so the GrabAPictureSettings class requires some way to make them public. It does so using these four properties.

' Works with the local random setting on frmMain.
Public Property LocalChecked() As Boolean
   Get
      Return _LocalChecked
   End Get
   Set(ByVal Value As Boolean)
      _LocalChecked = Value
   End Set
End Property
 
' Works with the remote random setting on frmMain
Public Property RemoteChecked() As Boolean
   Get
      Return _RemoteChecked
   End Get
   Set(ByVal Value As Boolean)
      _RemoteChecked = Value
   End Set
End Property
 
' Works with the collection of local resources.
Public Property LocalUris() As LocalUri()
   Get
      Return _LocalUris
   End Get
   Set(ByVal Value As LocalUri())
      _LocalUris = Value
   End Set
End Property
 
' Works with the collection of remote resources.
Public Property RemoteUris() As RemoteUri()
   Get
      Return _RemoteUris
   End Get
   Set(ByVal Value As RemoteUri())
      _RemoteUris = Value
   End Set
End Property

As you can see, there is nothing special about the properties. The reason these properties are relatively simple is that most of the work is done in the classes discussed in earlier posts. The WinWallpaper class, especially, does a lot of heavy lifting for this application.

It’s time to save the settings to disk. The result will be an XML file that contains two settings that determine the checked state of the Use Random Local Sources and Use Random Remote Sources checkboxes, along with two separate lists of wallpaper entries for local and remote sources. Here is the code used to save wallpaper settings to disk.

' Saves the settings to disk.
Public Shared Sub SaveSettings(ByVal Current As GrabAPictureSettings)
   ' Obtain a user-specific storage location for this application.
   Dim UserPath As String
   UserPath = _
      Environment.GetFolderPath( _
         Environment.SpecialFolder.ApplicationData) + _
         "\GrabAPicture"
 
   ' Create the path if necessary.
   If Not Directory.Exists(UserPath) Then
      Directory.CreateDirectory(UserPath)
   End If
 
   ' Create an XML serializer.
   Dim DataWrite As New XmlSerializer(GetType(GrabAPictureSettings))
 
   ' Create a stream writer to output the data.
   Dim Output As New StreamWriter(UserPath + "\AppData.Config")
 
   ' Save the settings.
   DataWrite.Serialize(Output, Current)
   Output.Close()
End Sub

The one question you might have at this point is how the application gets by with so little code. The answer is in the details, such as marking the LocalUri and RemoteUri classes serializable so that the .NET Framework does most of the work for you. In this case, the code begins by creating a user-specific path that includes the user’s application data folder and a subfolder named GrabAPicture. On my Windows 7 machine, this folder equates to C:\Users\John\AppData\Roaming\GrabAPicture. Of course, it’ll be different on your system (at least the name will be different unless we use the same log on name).

 

If you find that your knowledge of serialization is lacking, check out Rod Stephen’s site for additional information. Make sure you check out the Object Serialization tutorial as a starting point. Be sure to check out “Serialize and deserialize objects in Visual Basic .NET” and “Control serialization and deserialization with attributes in Visual Basic .NET” as well. In fact, Visual Basic developer’s should definitely check out Rod’s entire list of Software Engineering topics.

The example then checks for the existence of the target folder. If the folder doesn’t exist (it won’t the first time you use the application), the application creates it.

At this point, the application can create an XmlSerializer object of type GrabAPictureSettings named DataWrite. It’s important to remember that GrabAPictureSettings relies on all of the classes we’ve discussed to this point, including those Win32 API calls. Splitting the task up into a number of classes makes things look simple, when they’re really a little on the complex side.

In order to write data to disk, the code must also create a StreamWriter object named Output that points to the AppData.Config file in the UserPath folder discussed earlier. Finally, the code can save the Current settings (passed to SaveSettings() by the caller) to the Output using the DataWrite.Serialize() method. Here’s an example of what the output might look like on your system:

GrabAPicture0801

The output is actually quite readable and there isn’t anything unexpected in it. The XML file contains every wallpaper entry, both local and remote, that the user wants to use for the Desktop on a random basis.

Of course, you’re now asking yourself where this mysterious Content variable comes from. One way that the application generates it is to load settings from disk using the LoadSettings() method shown here (a future post will discuss techniques for working with content in situations where the data doesn’t already exist).

' Loads the settings from disk.
Public Shared Function LoadSettings() As GrabAPictureSettings
   Dim UserPath As String
   UserPath = _
      Environment.GetFolderPath( _
         Environment.SpecialFolder.ApplicationData) + _
         "\GrabAPicture"
 
   ' Determine whether the file exists.
   If Not File.Exists(UserPath + "\AppData.Config") Then
      ' It doesn't, so there aren't any settings.
      Return Nothing
   End If
 
   ' Create an XML serializer.
   Dim DataRead As New XmlSerializer(GetType(GrabAPictureSettings))
 
   ' Create a stream reader to load the data.
   Dim Input As New StreamReader(UserPath + "\AppData.Config")
 
   ' Load the settings.
   Dim Current As GrabAPictureSettings
   Current = CType(DataRead.Deserialize(Input), GrabAPictureSettings)
   Input.Close()
 
   ' Return the result.
   Return Current
End Function

The process is similar to saving the settings. The code begins by creating the appropriate UserPath variable, an XmlSerializer object named DataRead, and a StreamReader named Input. The main difference this time is that the application uses the DataRead.Deserialize() method to turn the XML in the AppData.Config file into settings that the application can use. Of course, this means converting the type of the output to type GrabAPictureSettings. The method returns Current as output to the caller.

Next week we’ll move back to frmMain. Now that you have a good idea of how the settings work, it’s time to see how the application puts them into practice. The GrabAPicture application has both a GUI and a command line interface. This next post will describe the command line interface so that you can begin to understand how this application makes Desktop wallpaper changes through a simple addition to the user’s Startup folder. In the meantime, please let me know if you have any questions at John@JohnMuellerBooks.com. You can find the next post in this series at Exploring the GrabAPicture Application (Part 9).