<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Comment Feed for Channel 9 - Check out this code! (Part II)</title>
	<atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/coding4fun/articles/Check-out-this-code-Part-II/RSS"></atom:link>
	<image>
		<url>http://ecn.channel9.msdn.com/o9/c4f/images/2195179_100.jpg</url>
		<title>Channel 9 - Check out this code! (Part II)</title>
		<link></link>
	</image>
	<description>
 






In my last article, I discussed a reusable library for communicating with Horizon Information Portal libraries.&amp;nbsp; In this column, find out how to use that library to create an application to run in your system tray to keep
 on top of your library books and other materials.&amp;nbsp; No more excuses for overdue fines!



Arian Kulp
Arian&#39;s Blog

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware: None
Download: 

C# Download
VB Download









Introduction
Part I of this article covered building the reusable class library (DLL) to communicate with libraries running the Horizon Information Portal software.&amp;nbsp; In addition to the DLL, I threw together a fairly simple application to support searching and showing
 checked out materials.&amp;nbsp; Hopefully if your local library uses the Horizon system, you&#39;ve already had a chance to try some things out. 
This article will take that reusable library and create a desktop application to expose more of the available search features, and allow multiple libraries and patrons to be monitored for upcoming and overdue books.&amp;nbsp; Concepts will include using a notification
 icon (appearing in the system tray), context menus (right-click), data binding, and serialization. 
The source code is available in both C# and VB (the download links are above the introduction).&amp;nbsp; The code will open in any version of Visual Studio, including the free Express editions.&amp;nbsp; To get started with the Express editions of Visual Studio, follow this
 link: Visual Studio 2005 Express Edition. 
Startup and Initialization
The API supports the concept of a library (Horizon.Library) and patrons (Horizon.Patron).&amp;nbsp; Patrons are associated with a library using a
HorizonSession object.&amp;nbsp; In theory this could allow one patron to be associated with more than one library, but in its current implementation, it&#39;s not likely to work since credentials are stored in the Patron object.&amp;nbsp; If someone belongs to
 several Horizon-based libraries, feel free to make changes to better support this! 
The Library also maintains a list of its users with its Users property.&amp;nbsp; Because of this, if you have a
Library object, you also have references to all of the users.&amp;nbsp; If you maintain a collection of
Library objects (assuming you want the ability to manage multiple libraries in your application) you have references to everything that you need.&amp;nbsp; In this application, I chose a generic List instance holding
Library objects, and made it a public property of the OptionsForm.&amp;nbsp; It&#39;s declared as a private variable, then exposed as a property: 
Visual Basic 
Private librariesValue As New List(Of Library)()

Public Property Libraries() As List(Of Library)
    Get
        Return librariesValue
    End Get
    Set(ByVal value As List(Of Library))
        librariesValue = value
    End Set
End Property
Visual C# 
private List&amp;lt;Library&amp;gt; librariesValue = new List&amp;lt;Library&amp;gt;();

public List&amp;lt;Library&amp;gt; Libraries
{
    get { return librariesValue; }
    set
    {
        librariesValue = value;
    }
}
After your user spends time entering library and patron information, it&#39;s probably a good idea to save it somewhere!&amp;nbsp; The easiest way is with XML or binary serialization, both built into the .NET Framework.&amp;nbsp; By serializing the
librariesValue collection object, you have effectively saved state for everything.&amp;nbsp; Serialization works using the
System.Runtime.Serialization namespace, and for binary format the
System.Runtime.Serialization.Formatters.Binary namespace.&amp;nbsp; Deserialization is the process of converting that binary or XML stream of data back into runtime objects.&amp;nbsp; The
Serialize and Deserialize methods handle this. 
Visual Basic 
Public Sub Serialize(ByVal file As String, ByVal libs As List(Of Library))
    Dim stream As Stream = New FileStream(file, System.IO.FileMode.Create)
    Dim formatter As IFormatter = New BinaryFormatter()
    formatter.Serialize(stream, libs)

    stream.Close()
End Sub

Public Function Deserialize(ByVal file As String) As List(Of Library)
    Try
        Dim stream As Stream = New FileStream(file, System.IO.FileMode.Open)

        Dim formatter As IFormatter = New BinaryFormatter()
        Dim itemsDeserialized As List(Of Library) = DirectCast(formatter.Deserialize(stream), List(Of Library))

        stream.Close()

        Return itemsDeserialized
    Catch
        Return New List(Of Library)()
    End Try
End Function
Visual C# 
public void Serialize(string file, List&amp;lt;Library&amp;gt; libs)
{
    Stream stream = new FileStream(file, System.IO.FileMode.Create);
    IFormatter formatter = new BinaryFormatter();
    formatter.Serialize(stream, libs);

    stream.Close();
}

public List&amp;lt;Library&amp;gt; Deserialize(string file)
{
    try
    {
        Stream stream = new FileStream(file, System.IO.FileMode.Open);

        IFormatter formatter = new BinaryFormatter();
        List&amp;lt;Library&amp;gt; itemsDeserialized = (List&amp;lt;Library&amp;gt;)formatter.Deserialize(stream);

        stream.Close();

        return itemsDeserialized;
    }
    catch
    {
        return new List&amp;lt;Library&amp;gt;();
    }
}
 
Once the library/patron data is restored, the MainForm.UpdateAllPatrons
method is invoked to retrieve details about each patron including books out, overdue, and fines owed.&amp;nbsp; This is done by looping through each library, and for each library looping through the patrons.&amp;nbsp; A brief summary of this information is then presented
 as a balloon tooltip from the notification icon.&amp;nbsp; You can also update this information by clicking
Update Patron Information from the notification icon. 

 
Figure 1 - Context menu for the notification icon (in the system tray) 
To manage the list of libraries and patrons, use the Configure 
menu command, or click Show Search Window to perform a search of your library holdings. 

 
Figure 2 - The Search dialog 
The Sort, Limit, and Search by fields come from the initialization of the library.&amp;nbsp; Values are in the
SortOptions, SearchLimits, and SearchOptions properties respectively. 
Databinding
After initialization, it&#39;s time to databind the search fields.&amp;nbsp; This is also repeated any time the current library is changed in the ComboBox.&amp;nbsp; Note that this only affects searching.&amp;nbsp; If you update patron information, it&#39;s always for all configured libraries.&amp;nbsp;
 When the current item changes for the librariesComboBox control, it calls
UpdateSearchFields: 
Visual Basic 
Private Sub UpdateSearchFields()
    materialTypesComboBox.DataSource = Nothing
    searchTypeComboBox.DataSource = Nothing
    sortComboBox.DataSource = Nothing

    If libraryValue IsNot Nothing Then
        &#39;Data-bind material types
        materialTypesComboBox.DataSource = libraryValue.SearchLimits
        materialTypesComboBox.DisplayMember = &amp;quot;Description&amp;quot;
        materialTypesComboBox.ValueMember = &amp;quot;Key&amp;quot;

        searchTypeComboBox.DataSource = libraryValue.SearchOptions
        searchTypeComboBox.DisplayMember = &amp;quot;Label&amp;quot;
        searchTypeComboBox.ValueMember = &amp;quot;Key&amp;quot;

        sortComboBox.DataSource = libraryValue.SortOptions
        sortComboBox.DisplayMember = &amp;quot;Label&amp;quot;
        sortComboBox.ValueMember = &amp;quot;Key&amp;quot;

        &#39; Must have one selected
        If libraryValue.SearchOptions.Count &amp;gt; 0 Then
            searchTypeComboBox.SelectedIndex = 0
        End If
    End If
End Sub

Visual C# 
private void UpdateSearchFields()
{
    materialTypesComboBox.DataSource = null;
    searchTypeComboBox.DataSource = null;
    sortComboBox.DataSource = null;

    if (lib != null)
    {
        //Data-bind material types
        materialTypesComboBox.DataSource = lib.SearchLimits;
        materialTypesComboBox.DisplayMember = &amp;quot;Description&amp;quot;;
        materialTypesComboBox.ValueMember = &amp;quot;Key&amp;quot;;

        searchTypeComboBox.DataSource = lib.SearchOptions;
        searchTypeComboBox.DisplayMember = &amp;quot;Label&amp;quot;;
        searchTypeComboBox.ValueMember = &amp;quot;Key&amp;quot;;

        sortComboBox.DataSource = lib.SortOptions;
        sortComboBox.DisplayMember = &amp;quot;Label&amp;quot;;
        sortComboBox.ValueMember = &amp;quot;Key&amp;quot;;

        if (lib.SearchOptions.Count &amp;gt; 0)
        {
            searchTypeComboBox.SelectedIndex = 0; // Must have one selected
        }
    }
}
Notice the call to set the data source to null/nothing for the three ComboBox controls.&amp;nbsp; If you update a collection and want to update a bound control to show the change, you need to first set the data source to null unless you use DataSource objects (which
 is a very cool way to go all out!).&amp;nbsp; In this case, it&#39;s not really necessary since it&#39;s a different collection for each library, but it&#39;s not a bad habit to get into.&amp;nbsp; You won&#39;t cause any problems anyway.&amp;nbsp; If the selected library turns out to be null/nothing
 (perhaps the last instance was deleted), the controls will be cleared out. 
Searching is mostly a matter of setting up the request and invoking the appropriate method.&amp;nbsp; The
SearchButton_Click event handler includes some error handling, so I&#39;ll just show the actual body here.&amp;nbsp; It&#39;s all about taking the values from the ComboBox controls.&amp;nbsp; I should point out that the
Aspect property is set based on what I can figure out from trying various requests.&amp;nbsp; I don&#39;t know for sure that is will work with all libraries.&amp;nbsp; The issue is that the basic default search only accepts a search type (title/author/keyword) without
 custom sorting or limits (by branch or collection).&amp;nbsp; The &amp;quot;subtab14&amp;quot; aspect seems to be the value for an &amp;quot;advanced&amp;quot; search.&amp;nbsp; It seems like per-library customizations may cause this to not always hold true. 
Visual Basic 
req.Aspect = &amp;quot;basic_search&amp;quot;
req.SearchTerm = searchTermTextBox.Text
req.Index = searchTypeComboBox.SelectedValue.ToString()

If materialTypesComboBox.SelectedValue IsNot Nothing Then
    req.Limit = materialTypesComboBox.SelectedValue.ToString()
    vreq.Aspect = &amp;quot;subtab14&amp;quot;
Else
    req.Limit = &amp;quot;&amp;quot;
End If

If sortComboBox.SelectedValue IsNot Nothing Then
    req.Sort = sortComboBox.SelectedValue.ToString()
    req.Aspect = &amp;quot;subtab14&amp;quot;
Else
    req.Sort = &amp;quot;&amp;quot;
End If

holdingsDataGridView.DataSource = libraryValue.Search(req)
Visual C# 
req.Aspect = &amp;quot;basic_search&amp;quot;;
req.SearchTerm = searchTermTextBox.Text;
req.Index = searchTypeComboBox.SelectedValue.ToString();

if (materialTypesComboBox.SelectedValue != null)
{
    req.Limit = materialTypesComboBox.SelectedValue.ToString();
    req.Aspect = &amp;quot;subtab14&amp;quot;;
}
else
    req.Limit = &amp;quot;&amp;quot;;

if (sortComboBox.SelectedValue != null)
{
    req.Sort = sortComboBox.SelectedValue.ToString();
    req.Aspect = &amp;quot;subtab14&amp;quot;;
}
else
    req.Sort = &amp;quot;&amp;quot;;

holdingsDataGridView.DataSource = lib.Search(req);
When you first launch the application, you won&#39;t actually see anything.&amp;nbsp; By design, the application can be run at startup and just keep an eye on what&#39;s checked out.&amp;nbsp; In my family, we have four accounts configured.&amp;nbsp;&amp;nbsp;In just&amp;nbsp;a few seconds, it logs into all
 accounts, reads the information, and presents a nice little popup with how many books are checked out and how much money is owed.&amp;nbsp; In the
Configuration dialog, you can set it to update this every n hours.&amp;nbsp; This will cause the popup to appear each time.&amp;nbsp; You can also manually update the information.&amp;nbsp; If you check the
Auto-Renew checkbox, books will renew the day before or day of (depending on when it notices).&amp;nbsp; Of course, if you&#39;ve already renewed or owe money, it might not have any effect. 

 
Figure 3 - General settings 
Final Note
As mentioned last time, the API was created by examining the XML to figure out inputs and outputs.&amp;nbsp; Due to the lack of documentation, and the apparent variation that exists between different library&#39;s implementation, some features don&#39;t work all that well
 on some libraries.&amp;nbsp; If you discover something that doesn&#39;t quite work right with your library, take a stab at fixing it and drop me a line.&amp;nbsp; Try to keep the fix general so it continues to work with other libraries. 
After creating the initial project, I noticed that SirsiDynix (the creators of Horizon Information Portal) are getting ready to release a new system,
Rome, that may or may not be anything like Horizon.&amp;nbsp; Time will tell!&amp;nbsp; At any rate, Rome isn&#39;t slated for release until the fourth quarter of 2007.&amp;nbsp; In the meantime, enjoy this! 
Next Steps
This application can definitely use some more polish.&amp;nbsp; Its spartan interface gets the job done, but could be much improved.&amp;nbsp; Try adding global hotkey support to trigger a search or update.&amp;nbsp; The search results pane could also stand some work.&amp;nbsp; The returned
 fields vary incredibly from one library to the next.&amp;nbsp; Author and Title are pretty standard, but you can&#39;t really count on anything.&amp;nbsp; One approach would be to actually examine your returned
Holding objects.&amp;nbsp; If you scan the collection of objects and find all of a given property are empty, hide the column.&amp;nbsp; Dynamically show only columns with values and you get a more relevant display. 
Conclusion
There&#39;s just something fun about interfacing with remote systems to add new data possibilities to your applications.&amp;nbsp;&amp;nbsp;Library data may not be as glamorous as commerce data, but it does have its practical side.&amp;nbsp; Reducing library fines is certainly worthwhile!&amp;nbsp;
 What else?&amp;nbsp; Mashups for searching multiple libraries and mapping where books are or using a tool like Greasemonkey (a Firefox plugin) to add library results to Amazon.com pages would be cool too.&amp;nbsp; Download
Visual Studio Express today and take it from here. 
 

 
A2rian Kulp is an independent software developer and writer working in the Midwest.&amp;nbsp; He has been coding since the fifth grade on various platforms, and also enjoys photography, nature, and spending time with his family.&amp;nbsp; Arian can be reached through his
 web site at http://www.ariankulp.com. 
</description>
	<link></link>
	<language>en</language>
	<pubDate>Wed, 22 May 2013 14:35:44 GMT</pubDate>
	<lastBuildDate>Wed, 22 May 2013 14:35:44 GMT</lastBuildDate>
	<generator>Rev9</generator>
	<item>
		<title>Re: Check out this code! (Part II)</title>
		<description>
			<![CDATA[ <p>In reference to your article:</p><p>Check out this code! (Part II)</p><p>Published 19 April 07 11:10 AM | Coding4Fun </p><p>I have a question about the part where you update the DataSource of the ComboBox to null.</p><p>materialTypesComboBox.DataSource = null;</p><p>How do you get this to work without getting a NullReferenceException? That's what I keep getting when I step through that line in my code. Any ideas?</p><p>Tom</p><p>posted by TomB</p>]]>
		</description>
		<link>http://channel9.msdn.com/coding4fun/articles/Check-out-this-code-Part-II#c633591216000000000</link>
		<pubDate>Thu, 09 Oct 2008 04:00:00 GMT</pubDate>
		<guid isPermaLink="true">http://channel9.msdn.com/coding4fun/articles/Check-out-this-code-Part-II#c633591216000000000</guid>
		<dc:creator>TomB</dc:creator>
	</item>
</channel>
</rss>