<?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>Channel 9</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9</title>
      <link>http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts</link>
    <language>en</language>
    <pubDate>Sat, 18 May 2013 15:09:54 GMT</pubDate>
    <lastBuildDate>Sat, 18 May 2013 15:09:54 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>4</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Harnessing the BackPack API - Part III</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This article is in series of BackPack API. It focuses on some of the underlying architecture of this application.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Michael K. Campbell</div>
<div class="entry_company"><a href="http://blog.angrypets.com/">AngryPets.com :: Blog</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Studio Express Editions</a>,<a href="http://www.backpackit.com/api/">BackPack API</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/BackPackAPI_PartIII_CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/BackPackAPI_PartIII_VB.msi">VB Download</a></li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>&nbsp;</p>
<h4>Stumbling Towards the Finish Line</h4>
<p>In my previous two articles, I indicated that my focus on the BackPack API would span three articles. In preparing for this article it became apparent that I was either going to have to cram an incredible amount of info into this last article or just gloss
 over a number of key points without giving them the coverage that they deserved. Neither of those options made sense, so I've decided to add an extra article—which will allow us to focus on some of the underlying architecture of our application a bit more
 prior to wrapping everything up in the fourth, and final, article. </p>
<h4>So What's Left?</h4>
<p>Our main goal in examining the BackPack API was to create a Windows Forms application that effectively mimics BackPack functionality while connected to the Internet, and that also provides the ability, while offline, to queue modifications that can be marshaled
 up to the BackPack servers once connectivity has been restored. In other words, we want to be able to take our BackPack data offline—using XML to store state, modifications, and other needed info. Of course, when editing offline, it will be nice to know which
 nodes (or data points) have been modified offline, and are therefore out of synch with the server—or master data. To accomplish this, we can just take advantage of the fact that
<b>TreeView</b> controls make it fairly easy to toggle an image associated with each node. Therefore, once a node becomes &quot;dirty,&quot; it will be visually flagged as such—then, once the change has been successfully made on the server, the icon can be toggled back
 to its original image—letting us know that the modification is complete, and that BackPack now looks like our local copy of the data.
</p>
<p>The final UI will look similar to the image below. A <b>TreeView</b> will allow us to drill into pages, and as we click on certain nodes, we'll have the ability to edit the corresponding data points. As you can see below, when a
<b>Task</b> is selected, the <b>Title</b> and <b>Completed</b> status are made available off to the left to allow for editing.
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/BackPackAPI_Part3_1.gif"><img title="Click here for larger image" alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/BackPackAPI_Part3_1_thumb.gif" width="490" border="0"></a>
</p>
<p><b>(Click image to zoom)</b> </p>
<p>If we make a change to the <b>Task's</b> title, and change the <b>Completion </b>
status, as follows: </p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/backpackapi_part3_2.gif" width="490" border="0">
</p>
<p>We'll want a visual indication that the node is in a non-synchronized or &quot;dirty&quot; state until it's been successfully synchronized with the server. Providing that indication will be as simple as providing an icon with an exclamation point and a pencil (if
 you've got good eyes) that indicates that the node, or the object it represents, is in the process of being modified.
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/backpackapi_part3_3.gif" border="0">
</p>
<p>Not until the modification is complete will the title of the node be updated to reflect the change, but the change will be made in our local copy of the data, and an operation to change the data on the BackPack servers will be dispatched asynchronously.
 In the following diagram, the flow would effectively be: </p>
<ol>
<li>User saves a change in the UI—which notifies the local data store. </li><li>The local data store records the info, and marshals the change to the BackPack servers (meanwhile the icon/state of the node in the UI is still flagged as dirty).
</li><li>The BackPack server responds, and the local data store is notified of the outcome, whereupon the local data store can do any additional processing of its local data if needed to bring it into sync with the master data stored on the servers.
</li><li>Once the local data store gets done processing the notification, it, in turn, raises a notification to the UI, letting it know about the status of the operation.
</li><li>The UI processes the notification, and modifies the UI as needed. </li></ol>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/backpackapi_part3_4.gif" border="0">
</p>
<p>But what if the application is offline? </p>
<h4>Taking Our BackPack Off-Road</h4>
<p>If the application is off-line, then the local data store isn't able to marshal the change up to the server, and won't be able to send back a notification to the UI that the change has been completed. Instead, the operation will be queued—and will be executed
 later, once connectivity is restored. Meanwhile, the &quot;dirty&quot; icon hangs out at the corresponding node on the
<b>TreeView</b> control—indicating to the user that the underlying node data is unsynchronized with the data on the server. That's all fine and well—but what happens if the user closes the application, with operations pending? Obviously when they restart the
 application, they'll want to see which nodes are still out of sync, or pending modification. That's where things get fun—because our local data store will now not only need to persist commands to be marshaled against the server, but will also need to persist
 pending operations so that their state can be accurately reflected in the UI when the user reloads the application in offline mode.
</p>
<p>The focus of this article, then, will be on the mechanism that we'll use to make this asynchronous, and potentially offline, communication between the UI, the local data store, and the remote BackPack servers possible. In this article we'll just work on
 the overall plumbing, and will focus on getting this process to work while online. Once the entire communication process is underway and working, making the whole thing work while offline isn't much more work—though we'll leave the offline details until the
 next article. </p>
<h5>Taming the User Interface </h5>
<p>One of the cool things about <b>TreeView</b> controls is that each corresponding
<b>TreeNode</b> object has a <b>Tag</b> property—an object that acts as a data-slot into which we can cram information about the object the node represents. In our case, at the most basic level, the
<b>Tag</b> property could therefore be used to flag whether a particular node represents a
<b>Page</b>, a <b>Note</b>, a <b>Task</b>, or something else. More importantly, we could also use it to keep track of the id of the page, or note, etc. being represented. But rather than cram a bunch of sloppy data into the
<b>Tag</b> property, I've opted to create a light-weight object called a <b>ResourceDescriptor</b>—which, well, describes a resource:
</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/backpackapi_part3_5.gif" width="490" border="0">
</p>
<p>Having this descriptor available will make processing <b>NodeClick</b> events much easier—we can just interrogate the clicked node's
<b>Tag</b> property to determine what kind of activity should be allowed, as follows:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> treeView1_NodeMouseClick(<span class="kwrd">object</span> sender, TreeNodeMouseClickEventArgs e)<br>{<br>    ResourceDescriptor rd = e.Node.Tag <span class="kwrd">as</span> ResourceDescriptor;<br>    <span class="kwrd">if</span>(rd == <span class="kwrd">null</span> || <span class="kwrd">this</span>.IsLockedNode(rd))<br>    {<br>        <span class="kwrd">this</span>.ResetFormFields();<br>        <span class="kwrd">return</span>;<br>    }<br>    <span class="kwrd">this</span>._currentResource = rd;<br>    <span class="kwrd">if</span> (e.Button == MouseButtons.Left)<br>        <span class="kwrd">this</span>.BindFormFields(rd);<br>    <span class="kwrd">else</span> <span class="kwrd">if</span> (e.Button == MouseButtons.Right)<br>    {<br>        <span class="kwrd">bool</span> showMenu = <span class="kwrd">false</span>;<br>        <span class="kwrd">this</span>.contextMenuNewTask.Visible = <span class="kwrd">false</span>;<br>        <span class="kwrd">this</span>.contextMenuNewPage.Visible = <span class="kwrd">false</span>;<br>        <span class="kwrd">this</span>.contextMenuNewNote.Visible = <span class="kwrd">false</span>;<br>        <span class="kwrd">switch</span> (rd.ResourceType)<br>        {<br>            <span class="kwrd">case</span> ResourceType.PageList:<br>                <span class="kwrd">this</span>.contextMenuNewPage.Visible = <span class="kwrd">true</span>;<br>                showMenu = <span class="kwrd">true</span>;<br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">case</span> ResourceType.NoteList:<br>                <span class="kwrd">this</span>.contextMenuNewNote.Visible = <span class="kwrd">true</span>;<br>                showMenu = <span class="kwrd">true</span>;<br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">case</span> ResourceType.TaskList:<br>                <span class="kwrd">this</span>.contextMenuNewTask.Visible = <span class="kwrd">true</span>;<br>                showMenu = <span class="kwrd">true</span>;<br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">default</span>:<br>                <span class="kwrd">break</span>;<br>        }<br><br>        <span class="kwrd">if</span> (showMenu)<br>        {<br>            <span class="kwrd">this</span>.treeView1.ContextMenuStrip.Show();<br>        }<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> treeView1_NodeMouseClick(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <br><span class="kwrd">ByVal</span> e <span class="kwrd">As</span> TreeNodeMouseClickEventArgs) <span class="kwrd">Handles</span> TreeView1.NodeMouseClick<br>    <span class="kwrd">Dim</span> rd <span class="kwrd">As</span> ResourceDescriptor = <span class="kwrd">CType</span>(e.Node.Tag, ResourceDescriptor)<br>    <span class="kwrd">If</span> ((rd <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">OrElse</span> <span class="kwrd">Me</span>.IsLockedNode(rd)) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>.ResetFormFields()<br>        <span class="kwrd">Return</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">Me</span>._currentResource = rd<br>    <span class="kwrd">If</span> (e.Button = MouseButtons.Left) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>.BindFormFields(rd)<br>    <span class="kwrd">ElseIf</span> (e.Button = MouseButtons.Right) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> showMenu <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <span class="kwrd">False</span><br>        <span class="kwrd">Me</span>.contextMenuNewPage.Visible = <span class="kwrd">False</span><br>        <span class="kwrd">Me</span>.contextMenuNewTask.Visible = <span class="kwrd">False</span><br>        <span class="kwrd">Me</span>.contextMenuNewNote.Visible = <span class="kwrd">False</span><br>        <span class="kwrd">Select</span> <span class="kwrd">Case</span> (rd.ResourceType)<br>            <span class="kwrd">Case</span> ResourceType.PageList<br>                <span class="kwrd">Me</span>.contextMenuNewPage.Visible = <span class="kwrd">True</span><br>                showMenu = <span class="kwrd">True</span><br>            <span class="kwrd">Case</span> ResourceType.NoteList<br>                <span class="kwrd">Me</span>.contextMenuNewNote.Visible = <span class="kwrd">True</span><br>                showMenu = <span class="kwrd">True</span><br>            <span class="kwrd">Case</span> ResourceType.TaskList<br>                <span class="kwrd">Me</span>.contextMenuNewTask.Visible = <span class="kwrd">True</span><br>                showMenu = <span class="kwrd">True</span><br>        <span class="kwrd">End</span> <span class="kwrd">Select</span><br><br>        <span class="kwrd">If</span> showMenu <span class="kwrd">Then</span><br>            <span class="kwrd">Me</span>.treeView1.ContextMenuStrip.Show()<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>As the code above indicates, if the node was right-clicked and it is a suitable container for child nodes (such as a
<b>PageList</b>, <b>NoteList</b>, or <b>TaskList</b>), then a corresponding context menu item can be toggled and made visible. If the node represents a piece of data that can be modified, the
<b>ResourceDescriptor</b> is dispatched to a method that will be tasked with altering the user interface and wiring it up to allow the end-user to edit the resource in question, as seen in the following code:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> BindFormFields(ResourceDescriptor descriptor)<br>{<br>    <span class="kwrd">this</span>.ResetFormFields();<br><br>    <span class="kwrd">this</span>._currentlyEditedResource = <span class="kwrd">this</span>._currentResource;<br>    <span class="kwrd">switch</span> (descriptor.ResourceType)<br>    {<br>        <span class="kwrd">case</span> ResourceType.Page:<br>            <span class="kwrd">this</span>.BindFormFormToEditPage(descriptor.PageId);<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> ResourceType.Link:<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> ResourceType.Note:<br>            <span class="kwrd">this</span>.BindFormToEditNote(descriptor.PageId, descriptor.ChildId);<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> ResourceType.Tag:<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> ResourceType.Task:<br>            <span class="kwrd">this</span>.BindFormToEditTask(descriptor.PageId, descriptor.ChildId);<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">default</span>:<br>            <span class="kwrd">break</span>;<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code><br>
</code></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> BindFormFields(<span class="kwrd">ByVal</span> descriptor <span class="kwrd">As</span> ResourceDescriptor)<br>    <span class="kwrd">Me</span>.ResetFormFields()<br><br>    <span class="kwrd">Me</span>._currentlyEditedResource = <span class="kwrd">Me</span>._currentResource<br>    <span class="kwrd">Select</span> <span class="kwrd">Case</span> (descriptor.ResourceType)<br>        <span class="kwrd">Case</span> ResourceType.Page<br>            <span class="kwrd">Me</span>.BindFormFormToEditPage(descriptor.PageId)<br>        <span class="kwrd">Case</span> ResourceType.Link<br>        <span class="kwrd">Case</span> ResourceType.Note<br>            <span class="kwrd">Me</span>.BindFormToEditNote(descriptor.PageId, descriptor.ChildId)<br>        <span class="kwrd">Case</span> ResourceType.Tag<br>        <span class="kwrd">Case</span> ResourceType.Task<br>            <span class="kwrd">Me</span>.BindFormToEditTask(descriptor.PageId, descriptor.ChildId)<br>    <span class="kwrd">End</span> <span class="kwrd">Select</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>This simple bit of code just evaluates the type of object being represented, and makes a subsequent dispatch into a method that will look up the object to edit, and bind its properties to the Winform. If the user wanted to edit a
<b>Page</b> object, the following code would be executed: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> BindFormFormToEditPage(<span class="kwrd">string</span> pageId)<br> {<br>    <span class="kwrd">this</span>.ResetFormFields();<br><br>    <span class="rem">// toggle field values.. </span><br>    <span class="kwrd">this</span>.txtTitle.Visible = <span class="kwrd">true</span>;<br>    <span class="kwrd">this</span>.txtBody.Visible = <span class="kwrd">true</span>;<br>    <span class="kwrd">this</span>.lblTitle.Text = <span class="str">&quot;Page Title&quot;</span>;<br>    <span class="kwrd">this</span>.lblTitle.Visible = <span class="kwrd">true</span>;<br>    <span class="kwrd">this</span>.lblBody.Text = <span class="str">&quot;Page Body&quot;</span>;<br>    <span class="kwrd">this</span>.lblBody.Visible = <span class="kwrd">true</span>;<br><br>    <span class="kwrd">if</span> (pageId != <span class="kwrd">null</span>)<br>    {<br>        Page page = <span class="kwrd">this</span>._pageManager.GetPageById(pageId);<br>        <span class="kwrd">this</span>.txtTitle.Text = page.Title;<br>        <span class="kwrd">this</span>.txtBody.Text = page.Body;<br>    }<br><br>    <span class="kwrd">this</span>.btnSave.Text = <span class="str">&quot;Save Page&quot;</span>;<br>    <span class="kwrd">this</span>.btnSave.Visible = <span class="kwrd">true</span>;<br><br>    <span class="kwrd">this</span>.txtTitle.Focus();<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> BindFormFormToEditPage(<span class="kwrd">ByVal</span> pageId <span class="kwrd">As</span> <span class="kwrd">String</span>)<br>    <span class="kwrd">Me</span>.ResetFormFields()<br><br>    <span class="rem">' toggle field values.. </span><br>    <span class="kwrd">Me</span>.txtTitle.Visible = <span class="kwrd">True</span><br>    <span class="kwrd">Me</span>.txtBody.Visible = <span class="kwrd">True</span><br>    <span class="kwrd">Me</span>.lblTitle.Text = <span class="str">&quot;Page Title&quot;</span><br>    <span class="kwrd">Me</span>.lblTitle.Visible = <span class="kwrd">True</span><br>    <span class="kwrd">Me</span>.lblBody.Text = <span class="str">&quot;Page Body&quot;</span><br>    <span class="kwrd">Me</span>.lblBody.Visible = <span class="kwrd">True</span><br><br>    <span class="kwrd">If</span> (<span class="kwrd">Not</span> (pageId) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> page <span class="kwrd">As</span> Page = <span class="kwrd">Me</span>._pageManager.GetPageById(pageId)<br>        <span class="kwrd">Me</span>.txtTitle.Text = page.Title<br>        <span class="kwrd">Me</span>.txtBody.Text = page.Body<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>    <span class="kwrd">Me</span>.btnSave.Text = <span class="str">&quot;Save Page&quot;</span><br>    <span class="kwrd">Me</span>.btnSave.Visible = <span class="kwrd">True</span><br><br>    <span class="kwrd">Me</span>.txtTitle.Focus()<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>If the <b>pageId</b> is null, then blank fields for the <b>Title</b> and <b>Body</b> will be displayed in the Winform. If the
<b>pageId</b> isn't null, the page represented by the node will be loaded from the
<b>PageManager</b> (our local data store), and the page's title and body will be bound to the Winform for editing.
</p>
<p>As you can see, <b>ResourceDescriptors</b> can be quite handy. They not only provide an easy way to determine what kind of an object a particular node represents—but they can also be used to painlessly retrieve that object from the
<b>PageManager</b> which serves as our local data store. And, while it's nice to be able to use a Node to look up its corresponding object, we'll eventually need that 'lookup' process to be a two-way street. In other words, we'll want and need the ability to
 find the <b>TreeNode</b> that represents a given piece of BackPack data. The easiest way to do this is to bind the
<b>ResourceDescriptor's</b> &quot;signature&quot; (its overridden <b>.ToString()</b> output) into a hash table with the node in question as nodes are initially created and bound to the Winform when pages are loaded. The following helper function handles the details for
 us: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> RegisterNode(TreeNode node)<br>{<br>    ResourceDescriptor rd = node.Tag <span class="kwrd">as</span> ResourceDescriptor;<br>    <span class="kwrd">if</span> (rd != <span class="kwrd">null</span>) <br>        <span class="kwrd">this</span>._nodeLookups.Add(rd.ToString(), node);<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> RegisterNode(<span class="kwrd">ByVal</span> node <span class="kwrd">As</span> TreeNode)<br>    <span class="kwrd">Dim</span> rd <span class="kwrd">As</span> ResourceDescriptor = <span class="kwrd">CType</span>(node.Tag, ResourceDescriptor)<br>    <span class="kwrd">If</span> (<span class="kwrd">Not</span> (rd) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>._nodeLookups.Add(rd.ToString, node)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>With this simple lookup in place, the UI can use a notification from the data store about a particular data point being updated to find the node that represents the modified data and refresh, or update, the UI as needed (to remove the &quot;dirty&quot; icon, and other
 things). </p>
<h4>ResourceDescriptors Go on a World Tour</h4>
<p>In addition to allowing simple access to information about the object that a particular node represents, a
<b>ResourceDescriptor</b> can also be used as part of a state object that can be sent clear into the
<b>BackPackGateway</b> object, and returned back to the user interface as part of an accompanying
<b>EventArgs</b> class announcing the completion of a remotely executed operation having completed. But, rather than pass it in all by its lonesome, we'll actually end up bundling it into a
<b>PendingOperation</b> object—which will not only describe the piece of data being modified, but can also be used to describe the operation being attempted.
</p>
<p><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913591/backpackapi_part3_6.gif" width="490" border="0">
</p>
<p>Having such an object will make &quot;bouncing&quot; data back and forth between our tiers much easier to manage. It will also provide an excellent way to serialize pending operations—which we'll look at in the next article.
</p>
<h4>The New Face of Modifications</h4>
<p>In the first article on the BackPack API, we looked at how to translate user input into dynamically generated XML that could then be sent to the BackPack servers. Now that we have an object model in place (created in the second BackPack API article), and
 a better UI, as well as accompanying &quot;descriptors&quot; to describe the objects and operations being attempted, the flow for modifying data has changed a good deal. For example, consider the code below which handles the assembly of user input to save a modified
 (or newly created) page: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SavePage(ResourceDescriptor descriptor)<br>{<br>    <span class="rem">// TODO: validate input:</span><br>    <span class="kwrd">string</span> newTitle = <span class="kwrd">this</span>.txtTitle.Text.Trim();<br>    <span class="kwrd">string</span> newBody = <span class="kwrd">this</span>.txtBody.Text.Trim();<br><br>    <span class="kwrd">if</span> (descriptor.PageId == <span class="kwrd">null</span>)<br>    {<br>        <span class="kwrd">string</span> tempId = <span class="kwrd">this</span>._pageManager.CreatePage(newTitle, newBody);<br><br>        ResourceDescriptor newPage = <span class="kwrd">new</span> ResourceDescriptor(tempId, <span class="kwrd">null</span>, ResourceType.Page);<br>        <span class="kwrd">this</span>.LockNode(newPage);<br>        <span class="kwrd">this</span>.FlagNodeAsDirty(newPage, OperationType.Create);<br>    }<br>    <span class="kwrd">else</span><br>    {<br>        Page page = <span class="kwrd">this</span>._pageManager.GetPageById(descriptor.PageId);<br><br>        <span class="kwrd">if</span> (newTitle != page.Title)<br>        {<br>            page.UpdateTitle(newTitle);<br>            <span class="kwrd">this</span>.FlagNodeAsDirty(descriptor, OperationType.Update);<br>        }<br><br>        <span class="kwrd">if</span> (newBody != page.Body)<br>        {<br>            page.UpdateBody(newBody);<br>            <span class="kwrd">this</span>.FlagNodeAsDirty(descriptor, OperationType.Update);<br>        }<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SavePage(<span class="kwrd">ByVal</span> descriptor <span class="kwrd">As</span> ResourceDescriptor)<br>    <span class="rem">' TODO: validate input:</span><br>    <span class="kwrd">Dim</span> newTitle <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtTitle.Text.Trim<br>    <span class="kwrd">Dim</span> newBody <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.txtBody.Text.Trim<br><br>    <span class="kwrd">If</span> (descriptor.PageId = <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> tempId <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>._pageManager.CreatePage(newTitle,<br>            newBody)<br>        <span class="kwrd">Dim</span> newPage <span class="kwrd">As</span> ResourceDescriptor = <span class="kwrd">New</span><br>             ResourceDescriptor(tempId, <span class="kwrd">Nothing</span>, ResourceType.Page)<br>        <span class="kwrd">Me</span>.LockNode(newPage)<br>        <span class="kwrd">Me</span>.FlagNodeAsDirty(newPage, OperationType.Create)<br>    <span class="kwrd">Else</span><br>        <span class="kwrd">Dim</span> page <span class="kwrd">As</span> Page = <br>             <span class="kwrd">Me</span>._pageManager.GetPageById(descriptor.PageId)<br><br>        <span class="kwrd">If</span> (newTitle &lt;&gt; page.Title) <span class="kwrd">Then</span><br>            page.UpdateTitle(newTitle)<br>            <span class="kwrd">Me</span>.FlagNodeAsDirty(descriptor, OperationType.Update)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>        <span class="kwrd">If</span> (newBody &lt;&gt; page.Body) <span class="kwrd">Then</span><br>            page.UpdateBody(newBody)<br>            <span class="kwrd">Me</span>.FlagNodeAsDirty(descriptor, OperationType.Update)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note that a <b>ResourceDescriptor</b> is passed into this method as the only argument—this descriptor is the
<b>Tag</b> corresponding to the last <b>TreeNode </b>to have been place in edit mode. Having the descriptor available in this method allows us to fetch a copy of the underlying object being modified and allows us to compare it to the currently attempted changes.
 Some simple logic determines if the requested operation represents the modification of an existing page, or the attempt to create a new page, and handles bundling up the corresponding user input as needed. Once that's complete, the method then dispatches the
 user data to the appropriate BackPack object for processing (if it's a page, the page exposes methods for modifying its
<b>Title</b> and <b>Body</b>, and if a new page is requested, the <b>PageManager</b> exposes a method for the creation of a new page). Once the actual operation to make the change has been routed to the appropriate object, there remains the task of toggling
 the node's icon to indicate that the underlying data is now out of sync. The &quot;toggling&quot; process is handled by a simple helper method that flags the node as dirty by changing its icon, and registering the node in a hash table that keeps a reference count to
 the current number of operations queued against the given node. If the operation involves the creation of a new object, then, in addition to being flagged as pending, the node is also locked—meaning that attempts to edit it (or add children) will be blocked—which
 needs to be the case, as we don't yet have an <b>Id</b> to use for modifying the object on the BackPack servers.
</p>
<p>Logic for translating user input into XML and for generating the URL to access on the servers remains largely the same, as can be seen in the following code that handles the creation of a new page on the
<b>PageManager</b>. </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">string</span> CreatePage(<span class="kwrd">string</span> title, <span class="kwrd">string</span> body)<br>{<br>    Page page = <span class="kwrd">new</span> Page(title, body);<br>    page.Id = PageManager.GenerateTemporaryObjectId(<span class="kwrd">typeof</span>(Page));<br><br>    <span class="kwrd">this</span>.AddPage(page);<br>    <br>    XmlDocument args = <span class="kwrd">new</span> XmlDocument();<br>    XmlElement pageNode = args.CreateElement(<span class="str">&quot;page&quot;</span>);<br>    XmlElement titleNode = args.CreateElement(<span class="str">&quot;title&quot;</span>);<br>    titleNode.InnerText = title;<br>    XmlElement description = args.CreateElement(<span class="str">&quot;description&quot;</span>);<br>    description.InnerText = body;<br><br>    pageNode.AppendChild(titleNode);<br>    pageNode.AppendChild(description);<br><br>    ResourceDescriptor rd = <span class="kwrd">new</span> ResourceDescriptor(page.Id, <span class="kwrd">null</span>, ResourceType.Page);<br>    PendingOperation op = <span class="kwrd">new</span> PendingOperation(rd, OperationType.Create, <span class="kwrd">null</span>);<br><br>    <span class="kwrd">string</span> methodUrl = <span class="str">&quot;/ws/pages/new&quot;</span>;<br><br>    <span class="kwrd">this</span>.InvokeOperation(methodUrl, pageNode, op);<br>    <span class="kwrd">return</span> page.Id;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<p><code></code></p>
<pre></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Function</span> CreatePage(<span class="kwrd">ByVal</span> title <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> body <span class="kwrd">As</span> <span class="kwrd">String</span>) <br>    <span class="kwrd">As</span> <span class="kwrd">String</span><br>    <span class="kwrd">Dim</span> page <span class="kwrd">As</span> Page = <span class="kwrd">New</span> Page(title, body)<br>    page.Id = PageManager.GenerateTemporaryObjectId(<span class="kwrd">GetType</span>(Page))<br><br>    <span class="kwrd">Me</span>.AddPage(page)<br><br>    <span class="kwrd">Dim</span> args <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument<br>    <span class="kwrd">Dim</span> pageNode <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;page&quot;</span>)<br>    <span class="kwrd">Dim</span> titleNode <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;title&quot;</span>)<br>    titleNode.InnerText = title<br>    <span class="kwrd">Dim</span> description <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;description&quot;</span>)<br>    description.InnerText = body<br><br>    pageNode.AppendChild(titleNode)<br>    pageNode.AppendChild(description)<br><br>    <span class="kwrd">Dim</span> rd <span class="kwrd">As</span> ResourceDescriptor = <span class="kwrd">New</span> ResourceDescriptor(page.Id, <br>         <span class="kwrd">Nothing</span>, ResourceType.Page)<br>    <span class="kwrd">Dim</span> op <span class="kwrd">As</span> PendingOperation = <span class="kwrd">New</span> PendingOperation(rd, <br>         OperationType.Create, <span class="kwrd">Nothing</span>)<br><br>    <span class="kwrd">Dim</span> methodUrl <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="str">&quot;/ws/pages/new&quot;</span><br><br>    <span class="kwrd">Me</span>.InvokeOperation(methodUrl, pageNode, op)<br>    <span class="kwrd">Return</span> page.Id<br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The big difference is the creation of a <b>ResourceDescriptor</b> to describe the object being passed for modification out to the BackPack servers (I could have just passed in the existing
<b>ResourceDescriptor</b> from the UI, but I didn't want them coupled that closely), as well as the creation of a
<b>PendingOperation</b> object used to describe the operation being attempted. Note, too, that a call to
<b>this.AddPage()</b> is also made in this method—before we even attempt to send our change to the BackPack Servers. This means that our local copy of the BackPack data has already been updated as if the operation had successfully completed. If the attempted
 operation fails we can rollback by interrogating the <b>PendingOperation</b> details and using the previous version of the object—if one was available (the third argument for creating a new
<b>PendingOperation</b> is a slot for an object representing the previous 'version' of the object that is being modified).
</p>
<p>When the operation is invoked, and routed to the <b>BackPackGateway</b>, the gateway effectively just ignores the
<b>PendingOperation</b> object sent in, and merely attaches it to the <b>EventArgs</b> object used to notify the page manager that the operation has completed. The
<b>PageManager</b> handles the event with the <b>GatewayResponded</b> method: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> GatewayResponded(<span class="kwrd">object</span> sender, RemoteOperationCompleteEventArgs e)<br>{<br>    <span class="rem">// handle the event (details covered below) </span><br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code><br>
</code></p>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> GatewayResponded(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>,<br>    <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> RemoteOperationCompleteEventArgs)<br>    <span class="rem">'handle the event (details covered below)</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The first thing that this method does is evaluate whether or not an error occurred—and then handles it accordingly (we'll cover rollbacks and other issues in the next article):
</p>
<p><b>Visual C#</b><code>&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode">    OperationCompleteEventArgs eventArgs = <span class="kwrd">null</span>;<br>    <span class="kwrd">if</span> (e.OperationStatus == CompletionStatus.Fail)<br>    {<br>        <span class="kwrd">if</span> (e.PendingOperation.OperationType == OperationType.Read)<br>            <span class="kwrd">throw</span> <span class="kwrd">new</span> Exception(<span class="str">&quot;Error Reading Data From Server&quot;</span>, e.Exception);<br><br>        eventArgs = <span class="kwrd">new</span> OperationCompleteEventArgs(<br>            e.PendingOperation, CompletionStatus.Fail, e.Exception);<br>    }<br>    <span class="kwrd">if</span> (eventArgs != <span class="kwrd">null</span>)<br>        <span class="kwrd">this</span>.OnDataOperationComplete(eventArgs);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code>&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">    Dim</span> eventArgs <span class="kwrd">As</span> OperationCompleteEventArgs = <span class="kwrd">Nothing</span><br>    <span class="kwrd">If</span> (e.OperationStatus = CompletionStatus.Fail) <span class="kwrd">Then</span><br>        <span class="kwrd">If</span> (e.PendingOperation.OperationType = OperationType.Read) <span class="kwrd">Then</span><br>            <span class="kwrd">Throw</span> <span class="kwrd">New</span> Exception(<span class="str">&quot;Error Reading Data From Server&quot;</span>, <br>                 e.Exception)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>        eventArgs = <span class="kwrd">New</span> OperationCompleteEventArgs(e.PendingOperation, <br>            CompletionStatus.Fail, e.Exception)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">If</span> (<span class="kwrd">Not</span> (eventArgs) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>.OnDataOperationComplete(eventArgs)<br>    <span class="kwrd">End</span> If</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>If there were no errors detected, the <b>PageManager</b> then needs to evaluate the operation type and do any additional processing necessary to bring the local data store into sync with the BackPack server—such as swapping out the
<b>tempId</b> with the <b>newId</b> returned by the BackPack Servers in the case of objects that were successfully created, as follows:
</p>
<p><b>Visual C#</b><code>&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd"></span>    <span class="kwrd">else</span><br>    {<br>        <span class="rem">// determine if extra processing is required and handle it if needed.</span><br>        <span class="kwrd">switch</span> (e.PendingOperation.OperationType)<br>        {<br>            <span class="kwrd">case</span> OperationType.Read:<br>                <span class="kwrd">if</span> (e.PendingOperation.Descriptor.ResourceType == ResourceType.PageList)<br>                    <span class="kwrd">this</span>.PagesListed(e.ResponseText);<br>                <span class="kwrd">else</span> <span class="kwrd">if</span> (e.PendingOperation.Descriptor.ResourceType == ResourceType.Page)<br>                    <span class="kwrd">this</span>.SinglePageReturned(e.ResponseText);<br>                <span class="rem">// this operation doesn't need to be announced to the UI (we're done)</span><br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">case</span> OperationType.Create:<br>                <span class="kwrd">this</span>.ReplaceTempIdWithPermanentId(e.PendingOperation, e.ResponseText);<br><br>                eventArgs = <span class="kwrd">new</span> OperationCompleteEventArgs(e.PendingOperation);<br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">case</span> OperationType.Remove:<br>                <span class="rem">// covered in the next article</span><br>                <span class="kwrd">break</span>;<br>            <span class="kwrd">default</span>:<br>                <span class="rem">// just let the UI know to unbind/etc the matching node:</span><br>                eventArgs = <span class="kwrd">new</span> OperationCompleteEventArgs(e.PendingOperation);<br>                <span class="kwrd">break</span>;<br>        }<br>    }<br><br>    <span class="rem">// remove the operation from the list of pending operations so that it won't be </span><br>    <span class="rem">//serialized upon form close.</span><br>    <span class="kwrd">if</span> (<span class="kwrd">this</span>._pendingOperations.Contains(e.PendingOperation))<br>        <span class="kwrd">this</span>._pendingOperations.Remove(e.PendingOperation);<br><br>    <span class="rem">// notify the UI/Winform if needed:</span><br>   <span class="kwrd"> if</span> (eventArgs != <span class="kwrd">null</span>)<br>        <span class="kwrd">this</span>.OnDataOperationComplete(eventArgs);</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code>&nbsp;&nbsp;&nbsp; </code></p>
<pre class="csharpcode"><span class="kwrd">     Else</span><br>        <span class="rem">' determine if extra processing is required and handle it if</span><br>        <span class="rem">' needed.</span><br>        <span class="kwrd">Select</span> <span class="kwrd">Case</span> (e.PendingOperation.OperationType)<br>            <span class="kwrd">Case</span> OperationType.Read<br>                <span class="kwrd">If</span> (e.PendingOperation.Descriptor.ResourceType =<br>                    ResourceType.PageList) <span class="kwrd">Then</span><br>                    <span class="kwrd">Me</span>.PagesListed(e.ResponseText)<br>                <span class="kwrd">ElseIf</span> (e.PendingOperation.Descriptor.ResourceType = <br>                        ResourceType.Page) <span class="kwrd">Then</span><br>                    <span class="kwrd">Me</span>.SinglePageReturned(e.ResponseText)<br>                <span class="kwrd">End</span> <span class="kwrd">If</span><br>                <span class="rem">' this operation doesn't need to be announced to the UI</span><br>                <span class="rem">' (we're done)</span><br>            <span class="kwrd">Case</span> OperationType.Create<br>                <span class="kwrd">Me</span>.ReplaceTempIdWithPermanentId(e.PendingOperation, <br>                    e.ResponseText)<br><br>                eventArgs = <br>                    <span class="kwrd">New</span> OperationCompleteEventArgs(e.PendingOperation)<br>            <span class="kwrd">Case</span> OperationType.Remove<br>                <span class="rem">' covered in the next article</span><br>            <span class="kwrd">Case</span> <span class="kwrd">Else</span><br>                eventArgs = <br>                    <span class="kwrd">New</span> OperationCompleteEventArgs(e.PendingOperation)<br>        <span class="kwrd">End</span> <span class="kwrd">Select</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>    <span class="rem">' remove the operation from the list of pending operations so that it</span><br>    <span class="rem">' won't be serialized upon form close.</span><br>    <span class="kwrd">If</span> <span class="kwrd">Me</span>._pendingOperations.Contains(e.PendingOperation) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>._pendingOperations.Remove(e.PendingOperation)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>    <span class="rem">' notify the UI/winform if needed:</span><br>    <span class="kwrd">If</span> (<span class="kwrd">Not</span> (eventArgs) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Me</span>.OnDataOperationComplete(eventArgs)<br>    <span class="kwrd">End</span> If</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In addition to any local processing needed, the <b>PageManager</b> also removes the
<b>PendingOperation</b> object from the internal list it is using to track pending operations (so that if the application is persisted, this operation won't end up being flagged as an artifact). Once the
<b>PageManager</b> is done with processing, it, in turn, raises an event notifying the UI of the completed operation—and the UI can then respond with logic designed to bring the state of the UI into sync with the local data store (which is now synchronized
 with the BackPack servers). Think of it sort of as a ripple effect: the UI plunks data into the data store (<b>PageManager</b>) which causes it to notify the remote servers—and once the remote operation is complete, the
<b>PageManager</b> is notified, and it ultimately notifies the UI. The code for handling that final notification, in the UI, is as follows:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<div class="postBody" id="da00c60d-7813-4288-b54a-0527b29a609d"><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style></div>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> DataOperationComplete(<span class="kwrd">object</span> sender, OperationCompleteEventArgs e)<br>{<br>    <span class="kwrd">if</span> (e.OperationStatus == CompletionStatus.Fail)<br>    {<br>        <span class="kwrd">if</span> (e.Operation.OperationType == OperationType.Read)<br>        {<br>            <span class="kwrd">string</span> inner = <span class="kwrd">string</span>.Empty;<br>            <span class="kwrd">if</span> (e.Exception != <span class="kwrd">null</span>)<br>                inner = System.Environment.NewLine &#43; e.Exception.Message;<br>            MessageBox.Show(<span class="str">&quot;Error Reading Pages From the Server.&quot;</span>);<br>        }<br>        <span class="kwrd">else</span><br>        {<br>            <span class="rem">// TODO:</span><br>            <span class="rem">// rollback the node to it's previous state. </span><br>        }<br>    }<br>    <span class="kwrd">else</span><br>    {<br>        <span class="kwrd">if</span> (e.Operation.OperationType == OperationType.Create)<br>        {<br>            ResourceDescriptor replacement = <span class="kwrd">null</span>;<br>            TreeNode modified = <br>               <span class="kwrd">this</span>._nodeLookups[e.Operation.Descriptor.ToString()]<br>               <span class="kwrd">as</span> TreeNode;<br>            <span class="kwrd">if</span> (modified != <span class="kwrd">null</span>)<br>            {<br>                <span class="kwrd">string</span> newId = (<span class="kwrd">string</span>)e.Operation.State;<br>                <br>                <span class="kwrd">if</span> (e.Operation.Descriptor.ResourceType == ResourceType.Page)<br>                {<br>                    replacement = <br>                       <span class="kwrd">new</span> ResourceDescriptor(newId, <span class="kwrd">null</span>, ResourceType.Page);<br>                }<br>                <span class="kwrd">else</span><br>                {<br>                    replacement = <span class="kwrd">new</span> ResourceDescriptor(<br>                        e.Operation.Descriptor.PageId, newId, <br>                        e.Operation.Descriptor.ResourceType);<br>                }<br><br>                <br><span class="kwrd">                lock</span> (<span class="kwrd">this</span>._nodeSync)<br>                {<br>                    <span class="kwrd">this</span>._nodeLookups.Remove(e.Operation.Descriptor.ToString());<br>                    <span class="kwrd">this</span>._nodeLookups.Add(replacement.ToString(), modified);<br><br>                    <span class="rem">// now modify the pending nodes:</span><br>                    <span class="kwrd">int</span> count = <br>                         (<span class="kwrd">int</span>)<span class="kwrd">this</span>._pendingNodes[e.Operation.Descriptor.ToString()];<br>                    <span class="kwrd">this</span>._pendingNodes.Remove(e.Operation.Descriptor.ToString());<br>                    <span class="kwrd">this</span>._pendingNodes.Add(replacement.ToString(), count);<br>                }<br>                <span class="kwrd">this</span>.BeginInvoke(<span class="kwrd">new</span> TreeNodeTagBinder(<span class="kwrd">this</span>.BindReplacementTag), <br>                    <span class="kwrd">new</span> <span class="kwrd">object</span>[] { modified, e.Operation.Descriptor, replacement });<br>            }<br>            <span class="kwrd">this</span>.UnlockNode(e.Operation.Descriptor);<br>            <span class="kwrd">this</span>.UnFlagNode(replacement);<br>        }<br>        <span class="kwrd">else</span><br>        {<br>            <span class="kwrd">this</span>.UnFlagNode(e.Operation.Descriptor);<br>        }<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> DataOperationComplete(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, _<br>      <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> OperationCompleteEventArgs)<br>    <span class="kwrd">If</span> (e.OperationStatus = CompletionStatus.Fail) <span class="kwrd">Then</span><br>        <span class="kwrd">If</span> (e.Operation.OperationType = OperationType.Read) <span class="kwrd">Then</span><br>            <span class="kwrd">Dim</span> inner <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty<br>            <span class="kwrd">If</span> (<span class="kwrd">Not</span> (e.Exception) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>                inner = (System.Environment.NewLine &#43; e.Exception.Message)<br>            <span class="kwrd">End</span> <span class="kwrd">If</span><br>            MessageBox.Show(<span class="str">&quot;Error Reading Pages From the Server.&quot;</span>)<br>        <span class="kwrd">Else</span><br>            <span class="rem">' TODO:</span><br>            <span class="rem">' rollback the node to it's previous state. </span><br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">ElseIf</span> (e.Operation.OperationType = OperationType.Create) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> replacement <span class="kwrd">As</span> ResourceDescriptor = <span class="kwrd">Nothing</span><br>        <span class="kwrd">Dim</span> modified <span class="kwrd">As</span> TreeNode = <br>            <span class="kwrd">CType</span>(<span class="kwrd">Me</span>._nodeLookups(e.Operation.Descriptor.ToString),<br>                TreeNode)<br>        <span class="kwrd">If</span> (<span class="kwrd">Not</span> (modified) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>            <span class="kwrd">Dim</span> newId <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">CType</span>(e.Operation.State, <span class="kwrd">String</span>)<br><br>            <span class="kwrd">If</span> (e.Operation.Descriptor.ResourceType = <br>             ResourceType.Page) <span class="kwrd">Then</span><br>                replacement = <span class="kwrd">New</span> ResourceDescriptor(newId, <span class="kwrd">Nothing</span>, <br>                 ResourceType.Page)<br>            <span class="kwrd">Else</span><br>                replacement = <span class="kwrd">New</span> <br>                 ResourceDescriptor(e.Operation.Descriptor.PageId, <br>                 newId, e.Operation.Descriptor.ResourceType)<br>            <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>            modified.Tag = replacement<br>            <span class="kwrd">SyncLock</span> <span class="kwrd">Me</span>._nodeSync<br>                    <br>              <span class="kwrd">Me</span>._nodeLookups.Remove(e.Operation.Descriptor.ToString)<br>              <span class="kwrd">Me</span>._nodeLookups.Add(replacement.ToString, modified)<br>              <span class="rem">' now modify the pending nodes:</span><br>              <span class="kwrd">Dim</span> count <span class="kwrd">As</span> <span class="kwrd">Integer</span> = <br>              <span class="kwrd">CType</span>(<span class="kwrd">Me</span>._pendingNodes(e.Operation.Descriptor.ToString), <br>              <span class="kwrd">Integer</span>)<br>                    <br>              <span class="kwrd">Me</span>._pendingNodes.Remove(e.Operation.Descriptor.ToString)<br>              <span class="kwrd">Me</span>._pendingNodes.Add(replacement.ToString, count)<br>            <span class="kwrd">End</span> <span class="kwrd">SyncLock</span><br>            <span class="kwrd">Me</span>.BeginInvoke(<span class="kwrd">New</span> TreeNodeTagBinder(<br>                <span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.BindReplacementTag), <span class="kwrd">New</span> <span class="kwrd">Object</span>() {<br>                modified, e.Operation.Descriptor, replacement})<br><br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">Me</span>.UnlockNode(e.Operation.Descriptor)<br>        <span class="kwrd">Me</span>.UnFlagNode(replacement)<br>    <span class="kwrd">Else</span><br>        <span class="kwrd">Me</span>.UnFlagNode(e.Operation.Descriptor)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>As you can see, that's a fairly hefty amount of code—and maybe it will deserve a refactoring in the final version of the application. The flow, however, isn't actually as complex as it looks at first blush. First the method checks to see if the operation
 failed remotely—in which case it will handle the rollback needed to put the UI back in sync with the BackPack servers. If the operation was successfully completed, things are very straight-forward UNLESS the operation was the creation of a new object. If it
 wasn't the creation of a new object, the descriptor accompanying the operation is handed off to a helper method that will un-toggle the &quot;dirty&quot; icon for the node in question. The helper method will also use the descriptor to &quot;reach back in&quot; to the underlying
 data store (where data is now synchronized with the servers) and grab the new title of the node, if there is one. It can then use the updated data to refresh the
<b>Node</b>'s title as needed. </p>
<p>If the pending operation was for the creation of an object, things are a bit messy—but effectively just involve replacing the
<b>tempId</b> used as a placeholder with the actual <b>Id</b> of the object as returned from BackPack. Additional work is then needed to make sure references to the temporary node are replaced with references to the node with its new
<b>Id</b>—so that modifications can be made, and children can be added. </p>
<h4>Are We There Yet?</h4>
<p>We're not quite there yet. But we've covered a decoupled way of marshalling data back and forth between our various tiers, which accomplishes two things: 1) it will let us provide end users with a visual indicator that their data is out of sync, and 2) because
 of the disconnected nature of everything, we'll be able to easily manage taking our application offline in the next article by persisting the state of our objects, as well as persisting information about pending operations.
</p>
<p>We still have a way to go yet, but for now you can take the current implementation for a test drive. You won't be able to delete objects with the application in its present state, but you will be able to modify pages, tasks, and notes—as well as create new
 ones by right-clicking the appropriate nodes. It may not seem like much to the uninitiated, but once you know what's going on under the covers, it's pretty cool to watch in action. Once you've done that, try tracing the flow of the various messages throughout
 the application, and see if you can spot the areas where serializing our application and its state make sense. Once you've found those, think about how you'd go about serializing them—we've covered almost all of the necessary information, from an XML standpoint,
 in previous articles—so there really won't be too much for us to do in the next article, apart from winding up a number of loose ends, ensuring serialization of state, and detecting network availability.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:56d40a9bb0494b85a6429e7600da924f">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-III</comments>
      <itunes:summary>



&amp;nbsp;
This article is in series of BackPack API. It focuses on some of the underlying architecture of this application.



Michael K. Campbell
AngryPets.com :: Blog

Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Studio Express Editions,BackPack API
Hardware: 
Download: 

C# Download
VB Download






&amp;nbsp; 
Stumbling Towards the Finish Line
In my previous two articles, I indicated that my focus on the BackPack API would span three articles. In preparing for this article it became apparent that I was either going to have to cram an incredible amount of info into this last article or just gloss
 over a number of key points without giving them the coverage that they deserved. Neither of those options made sense, so I&#39;ve decided to add an extra article—which will allow us to focus on some of the underlying architecture of our application a bit more
 prior to wrapping everything up in the fourth, and final, article.  
So What&#39;s Left?
Our main goal in examining the BackPack API was to create a Windows Forms application that effectively mimics BackPack functionality while connected to the Internet, and that also provides the ability, while offline, to queue modifications that can be marshaled
 up to the BackPack servers once connectivity has been restored. In other words, we want to be able to take our BackPack data offline—using XML to store state, modifications, and other needed info. Of course, when editing offline, it will be nice to know which
 nodes (or data points) have been modified offline, and are therefore out of synch with the server—or master data. To accomplish this, we can just take advantage of the fact that
TreeView controls make it fairly easy to toggle an image associated with each node. Therefore, once a node becomes &amp;quot;dirty,&amp;quot; it will be visually flagged as such—then, once the change has been successfully made on the server, the icon can be toggled back
 to its original image—letting us know that the modif</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-III</link>
      <pubDate>Tue, 31 Oct 2006 16:04:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-III</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913591_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913591_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michael K. Campbell</dc:creator>
      <itunes:author>Michael K. Campbell</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-III/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Building an XSL Transform Tool</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">Purpose of this tool is to apply the transformation in XSL on XML file and display the results.This tool is basically a Simple WinForm where the location of an XML file and a corresponding XSL file are specified.
 It then displays the results of the transformation in text box for review.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Michael K. Campbell</div>
<div class="entry_company"><a href="http://blogs.msdn.com/controlpanel/blogs/"></a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Studio Express Editions</a></div>
<div class="entry_details"><b>Hardware: </b></div>
<div class="entry_details"><strong>Download: </strong></div>
<ul>
<li>
<div class="entry_details"><a class="" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/XSLTFormer_CS.msi">C# Download</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/XSLTFormer_VB.msi">VB Download</a></div>
</li></ul>
<div class="entry_details">
<ul>
</ul>
</div>
</span></td>
</tr>
</tbody>
</table>
</span>
<p>A while back I got tired of looking for a simple solution to performing 'on the fly'
<b>XSL Transformations</b>. I didn't want some memory-hog tool to completely isolate me from the details of the transform through layers of abstraction—just a light-weight tool that would act as a simple transformation engine. I just needed something to run
 a transform based on my stylesheet and let me quickly check the results in an iterative fashion. I looked for a while, and didn't find anything like that available. So I built my own simple solution. It wasn't much—just a simple WinForm where I could specify
 the location of an XML file and a corresponding XSL file and then push a button to fire the results of the transformation to a text box for review. While that worked fine, I recently decided that my home-grown solution needed a bit of a face-lift. Nothing
 dramatic. Just a few tweaks to make it easier to fine-tune my stylesheets on the fly.
</p>
<h4>A Glorified Text Editor</h4>
<p>To keep things simple, I just wanted the added ability to edit my XML and XSL (mostly the latter) documents in the same tool that I used to transform them. I'd been using either an open instance of Visual Studio to edit them (nice, but heavy), or NotePad.
 In a perfect world, I'd get some of the key benefits of an editor like Visual Studio, but with the &quot;weight&quot; of something like NotePad. NotePad is actually fine for editing text files—only I hate the fact that it doesn't remember my tab position. In other words,
 if I've &quot;tabbed over&quot; three times (for formatting purposes) and type something followed by a carriage return, I'm back at the left margin, and not tabbed to the place where I was in the previous line. So, my thoughts on the upgrade were that if I could just
 get the text boxes where I would be doing my editing to remember my tab position, then I'd be happy. Only... I really like having tag completion in Visual Studio as well. It's not like I can't do it myself, but I certainly like having my tags closed automatically.
 So, I figured I needed both aspects in my new &quot;editor&quot; enabled version of my transform tool to make me happy.
</p>
<h4>Making Mikey Happy: Remembering Tab Position</h4>
<p>Figuring out how to remember tab positioning turned out to be tougher than I imagined—but in a strange way. Coding the solution wasn't very hard at all, and only took about half an hour to perfect. The hard part was figuring out that I had to code it myself.
 For some reason I figured that something in the Framework would make the task almost as easy as tweaking a property on one of the built-in
<b>TextBox</b> controls that ship with the Framework. After poring over the MSDN docs, trying to track down existing solutions on the web, and bugging a listserve that I spend a lot of time on, I decided to just write the functionality myself.
</p>
<p>Once I made the decision to code the functionality myself, the task became fairly easy. The trick was just to figure out what the number of preceding tabs were in the previous line, and plunk the same number of tabs in front of the cursor each time that
 a carriage return was detected. The logic to handle all of this was pretty simple and just revolved around getting a handle on the textbox housing the desired text, and then calculating the preceding line and existing tab count. Once those were located, all
 I had to do was insert a corresponding number of tabs into the textbox at the current position, and then advance the cursor by moving the
<b>SelectionStart</b> property: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">bool</span> HandleBlockTabbing(<span class="kwrd">object</span> sender)<br>{<br>    TextBox current = (TextBox)sender;<br>    <span class="kwrd">int</span> charIndex = current.SelectionStart;<br>    <span class="kwrd">string</span> work = current.Text.Substring(0, charIndex);<br><br>    <span class="kwrd">int</span> currentLineNumber = current.GetLineFromCharIndex(charIndex);<br><br>    <span class="rem">// the carriage return hasn't happened yet... </span><br>    <span class="rem">//      so the 'previous' line is the current one.</span><br>    <span class="kwrd">string</span> previousLineText;<br>    <span class="kwrd">if</span>(current.Lines.Length &lt;= currentLineNumber)<br>        previousLineText = current.Lines[current.Lines.Length - 1];<br>    <span class="kwrd">else</span><br>        previousLineText = current.Lines[currentLineNumber];<br><br>    <span class="kwrd">if</span> (previousLineText.StartsWith(<span class="str">&quot;\t&quot;</span>))<br>    {<br>        <span class="kwrd">string</span> tabs = <span class="kwrd">string</span>.Empty;<br>        <span class="rem">// first non-TAB character</span><br>        Match m = Regex.Match(previousLineText, <span class="str">&quot;[^\t]&quot;</span>);<br>        <span class="kwrd">if</span> (m.Success)<br>            tabs = previousLineText.Substring(0,<br>                previousLineText.IndexOf(m.Value));<br>        <span class="kwrd">else</span> <span class="rem">// there were only tabs (no other chars)</span><br>            tabs = previousLineText;<br><br>        <span class="kwrd">string</span> added = <span class="str">&quot;\r\n&quot;</span> &#43; tabs;<br><br>        current.Text = current.Text.Insert(charIndex, added);<br>        current.SelectionStart = charIndex &#43; added.Length;<br><br>        <span class="kwrd">return</span> <span class="kwrd">true</span>;<br>    }<br><br>    <span class="kwrd">return</span> <span class="kwrd">false</span>;<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> HandleBlockTabbing(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>) <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>    <span class="kwrd">Dim</span> current <span class="kwrd">As</span> SimpleEditBox = <span class="kwrd">CType</span>(sender, SimpleEditBox)<br>    <span class="kwrd">Dim</span> charIndex <span class="kwrd">As</span> <span class="kwrd">Integer</span> = current.SelectionStart<br>    <span class="kwrd">Dim</span> work <span class="kwrd">As</span> <span class="kwrd">String</span> = current.Text.Substring(0, charIndex)<br>    <span class="kwrd">Dim</span> currentLineNumber <span class="kwrd">As</span> <span class="kwrd">Integer</span> = <br>        current.GetLineFromCharIndex(charIndex)<br><br>    <span class="rem">' the carriage return hasn't happened yet... </span><br>    <span class="rem">'      so the 'previous' line is the current one.</span><br>    <span class="kwrd">Dim</span> previousLineText <span class="kwrd">As</span> <span class="kwrd">String</span><br><br>    <span class="kwrd">If</span> current.Lines.Length &lt;= currentLineNumber <span class="kwrd">Then</span><br>        previousLineText = current.Lines(current.Lines.Length - 1)<br>    <span class="kwrd">Else</span><br>        previousLineText = current.Lines(currentLineNumber)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>    <span class="kwrd">If</span> previousLineText.StartsWith(<span class="str">&quot;&quot;</span> &amp; vbTab) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> tabs <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty<br>        <span class="rem">' first non-TAB character</span><br>        <span class="kwrd">Dim</span> m <span class="kwrd">As</span> Match = Regex.Match(previousLineText, <span class="str">&quot;[^\t]&quot;</span>)<br>        <span class="kwrd">If</span> m.Success <span class="kwrd">Then</span><br>            tabs = previousLineText.Substring(0, <br>                previousLineText.IndexOf(m.Value))<br>        <span class="kwrd">Else</span><br>            tabs = previousLineText<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">Dim</span> added <span class="kwrd">As</span> <span class="kwrd">String</span> = (vbCrLf &#43; tabs)<br>        current.Text = current.Text.Insert(charIndex, added)<br>        current.SelectionStart = (charIndex &#43; added.Length)<br>        <span class="kwrd">Return</span> <span class="kwrd">True</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">Return</span> <span class="kwrd">False</span><br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>One big thing to note about the above code is that it's taking place in the <b>
KeyPress</b> event—so the carriage return hasn't really &quot;happened&quot; yet; it's currently in the state of being processed. But once the
<b>KeyPress</b> event is handled for a carriage return, the logic above makes a screen shot like the one below possible:
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/xslt_former_1.gif" border="0">
</p>
<p>The cool thing is that in the above screen shot, the logic discerned that the previous line was one tab over and then just inserted a carriage return plus a single tab into the current line of text (technically the third line of text, because the carriage
 return hasn't actually happened yet). Once that was put in place, the current selection was advanced to the end of the carriage return and the newly inserted tab. Then the textbox was &quot;told&quot; that the keystroke was handled (the
<code>return true</code> part of the code—more on that in a second), and the textbox therefore doesn't need to do any more processing on the keystroke (like add a carriage return of its own). The beauty of this approach is that there are no spooky characters
 in place; a simple BACKSPACE will remove the existing tab. It's like we've just used the textbox to do our typing for us, that's all.
</p>
<h4>Making Mikey Happy: Tag Completion</h4>
<p>I initially figured that tag completion would just be a question of using a regular expression to determine the name of the currently uncompleted tag (if there was one) each time a &quot;&gt;&quot; was detected, and then adding closing tags as needed. It turned out to
 be about that hard, only I needed to account for directives, comments, and empty tags as well. I also needed to be able to account for stray &quot;&gt;&quot; characters. The goal of my tag completion was to create functionality that was more like cruise control (a lazy
 person's driving aid), instead of an auto-pilot (where you'd effectively give up control of what was going on). To handle all of these contingencies, I just threw in a helper method where I could encapsulate all of the various permutations and just report
 to the caller (main logic) if it was to close the tag or not. Here's the code to handle the detection of a &quot;&gt;&quot; in the
<b>KeyPress</b> event: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">bool</span> HandleBlockTabbing(<span class="kwrd">object</span> sender)<br>{<br>    TextBox current = (TextBox)sender;<br>    <span class="kwrd">int</span> charIndex = current.SelectionStart;<br>    <span class="kwrd">string</span> work = current.Text.Substring(0, charIndex);<br><br>    <span class="kwrd">int</span> currentLineNumber = current.GetLineFromCharIndex(charIndex);<br><br>    <span class="rem">// the carriage return hasn't happened yet... </span><br>    <span class="rem">//      so the 'previous' line is the current one.</span><br>    <span class="kwrd">string</span> previousLineText;<br>    <span class="kwrd">if</span>(current.Lines.Length &lt;= currentLineNumber)<br>        previousLineText = current.Lines[current.Lines.Length - 1];<br>    <span class="kwrd">else</span><br>        previousLineText = current.Lines[currentLineNumber];<br><br>    <span class="kwrd">if</span> (previousLineText.StartsWith(<span class="str">&quot;\t&quot;</span>))<br>    {<br>        <span class="kwrd">string</span> tabs = <span class="kwrd">string</span>.Empty;<br>        <span class="rem">// first non-TAB character</span><br>        Match m = Regex.Match(previousLineText, <span class="str">&quot;[^\t]&quot;</span>);<br>        <span class="kwrd">if</span> (m.Success)<br>            tabs = previousLineText.Substring(0,<br>                previousLineText.IndexOf(m.Value));<br>        <span class="kwrd">else</span> <span class="rem">// there were only tabs (no other chars)</span><br>            tabs = previousLineText;<br><br>        <span class="kwrd">string</span> added = <span class="str">&quot;\r\n&quot;</span> &#43; tabs;<br><br>        current.Text = current.Text.Insert(charIndex, added);<br>        current.SelectionStart = charIndex &#43; added.Length;<br><br>        <span class="kwrd">return</span> <span class="kwrd">true</span>;<br>    }<br><br>    <span class="kwrd">return</span> <span class="kwrd">false</span>;<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> HandleBlockTabbing(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>) <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>    <span class="kwrd">Dim</span> current <span class="kwrd">As</span> SimpleEditBox = <span class="kwrd">CType</span>(sender, SimpleEditBox)<br>    <span class="kwrd">Dim</span> charIndex <span class="kwrd">As</span> <span class="kwrd">Integer</span> = current.SelectionStart<br>    <span class="kwrd">Dim</span> work <span class="kwrd">As</span> <span class="kwrd">String</span> = current.Text.Substring(0, charIndex)<br>    <span class="kwrd">Dim</span> currentLineNumber <span class="kwrd">As</span> <span class="kwrd">Integer</span> = <br>        current.GetLineFromCharIndex(charIndex)<br><br>    <span class="rem">' the carriage return hasn't happened yet... </span><br>    <span class="rem">'      so the 'previous' line is the current one.</span><br>    <span class="kwrd">Dim</span> previousLineText <span class="kwrd">As</span> <span class="kwrd">String</span><br><br>    <span class="kwrd">If</span> current.Lines.Length &lt;= currentLineNumber <span class="kwrd">Then</span><br>        previousLineText = current.Lines(current.Lines.Length - 1)<br>    <span class="kwrd">Else</span><br>        previousLineText = current.Lines(currentLineNumber)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br><br>    <span class="kwrd">If</span> previousLineText.StartsWith(<span class="str">&quot;&quot;</span> &amp; vbTab) <span class="kwrd">Then</span><br>        <span class="kwrd">Dim</span> tabs <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">String</span>.Empty<br>        <span class="rem">' first non-TAB character</span><br>        <span class="kwrd">Dim</span> m <span class="kwrd">As</span> Match = Regex.Match(previousLineText, <span class="str">&quot;[^\t]&quot;</span>)<br>        <span class="kwrd">If</span> m.Success <span class="kwrd">Then</span><br>            tabs = previousLineText.Substring(0, <br>                previousLineText.IndexOf(m.Value))<br>        <span class="kwrd">Else</span><br>            tabs = previousLineText<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">Dim</span> added <span class="kwrd">As</span> <span class="kwrd">String</span> = (vbCrLf &#43; tabs)<br>        current.Text = current.Text.Insert(charIndex, added)<br>        current.SelectionStart = (charIndex &#43; added.Length)<br>        <span class="kwrd">Return</span> <span class="kwrd">True</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">Return</span> <span class="kwrd">False</span><br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note that, in many ways, it's very similar to the code that handles tabbing: it just determines if characters need to be added, and then inserts them if needed. The difference is that it only advances the cursor one space when it's done doing the inserting
 task, so as to place the cursor between the beginning and ending tags. Whether or not the tag needs to be closed is decided by the following bit of helper logic:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">bool</span> CurrentPositionNeedsClosingTag(<span class="kwrd">string</span> input)<br>{<br>    <span class="kwrd">string</span> scrubbedText = input.Replace(<span class="str">&quot;\r&quot;</span>, <span class="kwrd">string</span>.Empty);<br>    scrubbedText = scrubbedText.Replace(<span class="str">&quot;\n&quot;</span>, <span class="kwrd">string</span>.Empty);<br>    scrubbedText = scrubbedText.Replace(<span class="str">&quot; &quot;</span>, <span class="kwrd">string</span>.Empty);<br>    <span class="rem">// check lots of various tag ending types, and then other issues/hacks</span><br><br>    <span class="rem">// ignore directives, comments, and empty tags:</span><br>    <span class="kwrd">bool</span> isDirective = scrubbedText.EndsWith(<span class="str">&quot;?&quot;</span>);<br>    <span class="kwrd">bool</span> isComment = scrubbedText.EndsWith(<span class="str">&quot;--&quot;</span>);<br>    <span class="kwrd">bool</span> isEmptyTag = scrubbedText.EndsWith(<span class="str">&quot;/&quot;</span>);<br>    <span class="kwrd">if</span> (isDirective || isComment || isEmptyTag)<br>        <span class="kwrd">return</span> <span class="kwrd">false</span>;<br><br>    <span class="rem">// watch out for stray tags and truly empty tags (&quot;&lt;&gt;&quot;)</span><br>    <span class="kwrd">if</span> (scrubbedText.EndsWith(<span class="str">&quot;&gt;&quot;</span>) || scrubbedText.EndsWith(<span class="str">&quot;&lt;&gt;&quot;</span>))<br>        <span class="kwrd">return</span> <span class="kwrd">false</span>;<br><br>    <span class="rem">// watch out for explicit closing tags </span><br>    <span class="rem">//      (&quot;&lt;/endMyTagByHand&gt;&quot; - don't want: &quot;&lt;/end&gt;&lt;//end&gt;&quot;)</span><br>    <span class="rem">//  HACK: should be done with a regex.. </span><br>    <span class="kwrd">int</span> position = scrubbedText.LastIndexOf(<span class="str">&quot;&lt;&quot;</span>);<br>    <span class="kwrd">if</span> (scrubbedText.Substring(position).StartsWith(<span class="str">&quot;&lt;/&quot;</span>))<br>        <span class="kwrd">return</span> <span class="kwrd">false</span>;<br><br>    <span class="kwrd">return</span> <span class="kwrd">true</span>;<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> CurrentPositionNeedsClosingTag(<span class="kwrd">ByVal</span> input <span class="kwrd">As</span> <span class="kwrd">String</span>) <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>    <span class="kwrd">Dim</span> scrubbedText <span class="kwrd">As</span> <span class="kwrd">String</span> = input.Replace(vbCr, <span class="kwrd">String</span>.Empty)<br>    scrubbedText = scrubbedText.Replace(vbLf, <span class="kwrd">String</span>.Empty)<br>    scrubbedText = scrubbedText.Replace(<span class="str">&quot; &quot;</span>, <span class="kwrd">String</span>.Empty)<br>    <span class="rem">' check lots of various tag ending types, and then other issues/hacks</span><br>    <span class="rem">' ignore directives, comments, and empty tags:</span><br>    <span class="kwrd">Dim</span> isDirective <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = scrubbedText.EndsWith(<span class="str">&quot;?&quot;</span>)<br>    <span class="kwrd">Dim</span> isComment <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = scrubbedText.EndsWith(<span class="str">&quot;--&quot;</span>)<br>    <span class="kwrd">Dim</span> isEmptyTag <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = scrubbedText.EndsWith(<span class="str">&quot;/&quot;</span>)<br>    <span class="kwrd">If</span> (isDirective _<br>                <span class="kwrd">OrElse</span> (isComment <span class="kwrd">OrElse</span> isEmptyTag)) <span class="kwrd">Then</span><br>        <span class="kwrd">Return</span> <span class="kwrd">False</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="rem">' watch out for stray tags and truly empty tags (&quot;&lt;&gt;&quot;)</span><br>    <span class="kwrd">If</span> (scrubbedText.EndsWith(<span class="str">&quot;&gt;&quot;</span>) <span class="kwrd">OrElse</span> scrubbedText.EndsWith(<span class="str">&quot;&lt;&gt;&quot;</span>)) <br>    <span class="kwrd">Then</span><br>        <span class="kwrd">Return</span> <span class="kwrd">False</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="rem">' watch out for explicit closing tags </span><br>    <span class="rem">'      (&quot;&lt;/endMyTagByHand&gt;&quot; - don't want: &quot;&lt;/end&gt;&lt;//end&gt;&quot;)</span><br>    <span class="rem">'  HACK: should be done with a regex.. </span><br>    <span class="kwrd">Dim</span> position <span class="kwrd">As</span> <span class="kwrd">Integer</span> = scrubbedText.LastIndexOf(<span class="str">&quot;&lt;&quot;</span>)<br>    <span class="kwrd">If</span> scrubbedText.Substring(position).StartsWith(<span class="str">&quot;&lt;/&quot;</span>) <span class="kwrd">Then</span><br>        <span class="kwrd">Return</span> <span class="kwrd">False</span><br>    <span class="kwrd">End</span> <span class="kwrd">If</span><br>    <span class="kwrd">Return</span> <span class="kwrd">True</span><br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Once in place, the tag completion turned out to be pretty spiffy. It won't close comments, directives, or empty tags (i.e.
<code>&lt;tag /&gt;</code>); just open tags, even ones that span multiple lines: </p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/xslt_former_2.gif" border="0">
</p>
<p>Coupled with the &quot;tab memory&quot; functionality, I now had enough editor functionality to make me happy.
</p>
<h4>Making Consumers Happy: Subclassing</h4>
<p>When I was first testing out the tabbing and tag-completion logic, I just did it in a WinForm, and handled the
<b>KeyPress</b> event. My long-term goal, though, was to create a subclass of <b>
System.Windows.Forms.TextBox</b> that would encapsulate this logic away to make reuse much easier. Imagine trying to handle tabbing and tag-completion for three textboxes on the same form, for example; it could be done, but wouldn't be pretty. Creating the
 subclass of <b>TextBox</b> was very easy. I just added a new user control to my current project, changed its inheritance from
<b>UserControl</b> to <b>TextBox</b> and then dropped in the code as follows: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">using</span> System;<br><span class="kwrd">using</span> System.Collections.Generic;<br><span class="kwrd">using</span> System.ComponentModel;<br><span class="kwrd">using</span> System.Drawing;<br><span class="kwrd">using</span> System.Data;<br><span class="kwrd">using</span> System.Text;<br><span class="kwrd">using</span> System.Windows.Forms;<br><span class="kwrd">using</span> System.Text.RegularExpressions;<br><br><span class="kwrd">namespace</span> XSLT_Former<br>{<br>    <br>    <span class="kwrd">public</span> <span class="kwrd">partial</span> <span class="kwrd">class</span> SimpleEditorBox : TextBox<br>    {<br>        <span class="kwrd">public</span> SimpleEditorBox()<br>        {<br>            InitializeComponent();<br><br>                <span class="rem">// make sure that tab and enter are allowed by</span><br>                <span class="rem">// default in this specialized text box:</span><br>            <span class="kwrd">base</span>.AcceptsReturn = <span class="kwrd">true</span>;<br>            <span class="kwrd">base</span>.AcceptsTab = <span class="kwrd">true</span>;<br>        }<br><br>        <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnKeyPress(KeyPressEventArgs e)<br>        {<br>            <span class="kwrd">if</span> (e.KeyChar == 13) <span class="rem">// enter/carriage return</span><br>                e.Handled = <span class="kwrd">this</span>.HandleBlockTabbing(<span class="kwrd">this</span>);<br>            <span class="kwrd">if</span> (e.KeyChar == <span class="str">'&gt;'</span>)<br>                e.Handled = <span class="kwrd">this</span>.HandleTagCompletion(<span class="kwrd">this</span>);<br><br>            <span class="kwrd">base</span>.OnKeyPress(e);<br>        }<br>        <span class="kwrd">private</span> <span class="kwrd">bool</span> HandleBlockTabbing(<span class="kwrd">object</span> sender)<br>        {<br>             <span class="rem">// elided - code same as above</span><br>        }<br><br>        <span class="kwrd">private</span> <span class="kwrd">bool</span> HandleTagCompletion(<span class="kwrd">object</span> sender)<br>        {<br>             <span class="rem">// elided - code same as above </span><br>        }<br><br>        <span class="kwrd">private</span> <span class="kwrd">bool</span> CurrentPositionNeedsClosingTag(<span class="kwrd">string</span> input)<br>        {<br>             <span class="rem">// elided - code same as above</span><br>        }<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Imports</span> System.Text.RegularExpressions<br><br><span class="kwrd">Public</span> <span class="kwrd">Class</span> SimpleEditBox<br>    <span class="kwrd">Inherits</span> System.Windows.Forms.TextBox<br><br>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> <span class="kwrd">New</span>()<br>        <span class="rem">' This call is required by the Windows Form Designer.</span><br>        InitializeComponent()<br><br>        <span class="kwrd">MyBase</span>.AcceptsReturn = <span class="kwrd">True</span><br>        <span class="kwrd">MyBase</span>.AcceptsTab = <span class="kwrd">True</span><br>    <span class="kwrd">End</span> <span class="kwrd">Sub</span><br><br>    <span class="kwrd">Protected</span> <span class="kwrd">Overrides</span> <span class="kwrd">Sub</span> OnKeyPress(<span class="kwrd">ByVal</span> e <span class="kwrd">As</span> KeyPressEventArgs)<br>        <span class="kwrd">If</span> (e.KeyChar = <span class="kwrd">CType</span>(ChrW(13), <span class="kwrd">Char</span>)) <span class="kwrd">Then</span><br>            e.Handled = <span class="kwrd">Me</span>.HandleBlockTabbing(<span class="kwrd">Me</span>)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">If</span> (e.KeyChar = <span class="kwrd">CType</span>(ChrW(62), <span class="kwrd">Char</span>)) <span class="kwrd">Then</span><br>            e.Handled = <span class="kwrd">Me</span>.HandleTagCompletion(<span class="kwrd">Me</span>)<br>        <span class="kwrd">End</span> <span class="kwrd">If</span><br>        <span class="kwrd">MyBase</span>.OnKeyPress(e)<br>    <span class="kwrd">End</span> <span class="kwrd">Sub</span><br><br>    <span class="kwrd">Private</span> <span class="kwrd">Function</span> HandleBlockTabbing(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>) <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>        <span class="rem">' elided - code same as above</span><br>    <span class="kwrd">End</span> <span class="kwrd">Function</span><br><br>    <span class="kwrd">Private</span> <span class="kwrd">Function</span> HandleTagCompletion(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>) <br>        <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>        <span class="rem">' elided - code same as above</span><br>    <span class="kwrd">End</span> <span class="kwrd">Function</span><br><br>    <span class="kwrd">Private</span> <span class="kwrd">Function</span> CurrentPositionNeedsClosingTag(<span class="kwrd">ByVal</span> input <span class="kwrd">As</span> <span class="kwrd">String</span>)<br>        <span class="kwrd">As</span> <span class="kwrd">Boolean</span><br>        <span class="rem">' elided - code same as above</span><br>    <span class="kwrd">End</span> <span class="kwrd">Function</span><br><span class="kwrd">End</span> Class</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>As you can see, nothing special. The <b>KeyPress</b> event is no longer being handled; rather, the
<b>OnKeyPress</b> method has been safely overridden such that this control can be further sub classed if desired. The big plus, of course, is that dropping a
<b>SimpleEditBox</b> onto a WinForm provides a textbox that now remembers tab position and closes XML (and HTML) tags.
</p>
<h4>Creating a Work Area </h4>
<p>With a <b>SimpleEditorBox</b> control now available to handle the whiz-bang features for text editing, it was time to create a WinForm that I could use as a work area. In it I needed an area to display the XML document, an XSL document (or my stylesheet)
 as well as the output. I wanted all three areas to editable, but maximizing the space for each area would have been problematic to try and manage. So I cheated and just used two splitter controls to allow a high degree of flexibility at run time. The first
 splitter divided the top (work area) from the bottom (output/results area) so that either section could be sized as needed. The second splitter—placed in the top half of the previous splitter—was to divide the XML work area from the XSL work area as follows:
</p>
<p><img height="372" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/xslt_former_3.gif" width="490" border="0">
</p>
<p>Each work area was then fitted with a few simple controls to allow for the loading and saving of files. A button to execute the transform was placed in the bottom of the form, which only becomes enabled once both work areas have a file loaded. By playing
 around with the Anchor properties for each control and <b>GroupBox</b>, each work area not only retains a decent perspective when the Winform is maximized, but as the sliders are moved around to focus on one are or the other, the other two areas maintain a
 decent aspect ratio as well (even when seriously &quot;scrunched&quot; so as to appear inside an image like the one below):
</p>
<p><img height="365" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913470/xslt_former_4.gif" width="490" border="0">
</p>
<p>As seen in the above image, I'm focusing my attention on the transform, where I've dedicated more of my real estate by tugging on the splitter bars to the desired sizing. However, the output and XML areas are still coherent and could easily become the focus
 of my efforts just through some more dragging on the darkened splitter bars. </p>
<h4>Doing the Transform</h4>
<p>The logic to handle the transform itself ends up being some pretty simple code. All it needs to be able to do is stream the contents of the XML and XSL
<b>SimpleEditBoxes</b> in as XML, and run them through a transform. </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> TransformOutput()<br>{<br>    <span class="kwrd">string</span> xml = <span class="kwrd">this</span>.edtXml.Text.Trim();<br>    <span class="kwrd">string</span> xsl = <span class="kwrd">this</span>.edtXsl.Text.Trim();<br><br>    <span class="kwrd">try</span><br>    {<br>        <span class="rem">// stream the xml:</span><br>        <span class="kwrd">byte</span>[] data = Encoding.UTF8.GetBytes(xml);<br>        MemoryStream ms = <span class="kwrd">new</span> MemoryStream(data);<br><br>        XmlReader input = XmlReader.Create(ms); <span class="rem">// to allow modification by xform</span><br><br>        <span class="rem">// load the xsl:</span><br>        XmlDocument stylesheet = <span class="kwrd">new</span> XmlDocument();<br>        stylesheet.LoadXml(xsl);<br><br>        XslCompiledTransform transform = <span class="kwrd">new</span> XslCompiledTransform();<br>        transform.Load(stylesheet);<br><br>        <span class="rem">// create output streams:</span><br>        MemoryStream buffer = <span class="kwrd">new</span> MemoryStream();<br>        StreamWriter sw = <span class="kwrd">new</span> StreamWriter(buffer);<br><br>        <span class="rem">// transform the document:</span><br>        transform.Transform(input, <span class="kwrd">null</span>, sw);<br><br>        <span class="rem">// turn results into a string:</span><br>        <span class="kwrd">byte</span>[] chars = buffer.ToArray();<br>        <span class="kwrd">string</span> output = Encoding.UTF8.GetString(chars);<br><br>        <span class="kwrd">this</span>.edtOut.Text = output;<br><br>        <span class="kwrd">this</span>.btnSaveOutput.Enabled = <span class="kwrd">true</span>;<br>    }<br>    <span class="kwrd">catch</span> (Exception ex)<br>    {<br>        <span class="kwrd">this</span>.edtOut.Text = <span class="str">&quot;Error Occurred: &quot;</span> &#43; Environment.NewLine &#43; ex.Message;<br>    }<br>}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> TransformOutput()<br>    <span class="kwrd">Dim</span> xml <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.edtXml.Text.Trim<br>    <span class="kwrd">Dim</span> xsl <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>.edtXsl.Text.Trim<br>    <span class="kwrd">Try</span><br>        <span class="rem">' stream the xml:</span><br>        <span class="kwrd">Dim</span> data() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = Encoding.UTF8.GetBytes(xml)<br>        <span class="kwrd">Dim</span> ms <span class="kwrd">As</span> MemoryStream = <span class="kwrd">New</span> MemoryStream(data)<br>        <span class="kwrd">Dim</span> input <span class="kwrd">As</span> XmlReader = XmlReader.Create(ms)<br>        <span class="rem">' to allow modification by xform</span><br>        <span class="rem">' load the xsl:</span><br>        <span class="kwrd">Dim</span> stylesheet <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument<br>        stylesheet.LoadXml(xsl)<br>        <span class="kwrd">Dim</span> transform <span class="kwrd">As</span> XslCompiledTransform = <span class="kwrd">New</span> XslCompiledTransform<br>        transform.Load(stylesheet)<br>        <span class="rem">' create output streams:</span><br>        <span class="kwrd">Dim</span> buffer <span class="kwrd">As</span> MemoryStream = <span class="kwrd">New</span> MemoryStream<br>        <span class="kwrd">Dim</span> sw <span class="kwrd">As</span> StreamWriter = <span class="kwrd">New</span> StreamWriter(buffer)<br>        <span class="rem">' transform the document:</span><br>        transform.Transform(input, <span class="kwrd">Nothing</span>, sw)<br>        <span class="rem">' turn results into a string:</span><br>        <span class="kwrd">Dim</span> chars() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = buffer.ToArray<br>        <span class="kwrd">Dim</span> output <span class="kwrd">As</span> <span class="kwrd">String</span> = Encoding.UTF8.GetString(chars)<br>        <span class="kwrd">Me</span>.edtOut.Text = output<br>        <span class="kwrd">Me</span>.btnSaveOutput.Enabled = <span class="kwrd">True</span><br>    <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception<br>        <span class="kwrd">Me</span>.edtOut.Text = (<span class="str">&quot;Error Occurred: &quot;</span> _<br>                    &#43; (Environment.NewLine &#43; ex.Message))<br>    <span class="kwrd">End</span> <span class="kwrd">Try</span><br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Exceptions are handled in a very simple fashion by just outputting the details of the exception to the output window. If no exception occurs, then the transform results are written to the output window. There they can be modified as needed or saved to disk
 using the menu options or button control available. </p>
<p>And there it is: a simple tool that allows you to get your hands dirty with the gory details of XSLT, along with a simple button that will render the transform for you whenever you are ready. The simple additions to the editor panes make it easier to perform
 ad hoc modification of the XML and XSL documents, and being able to render the transform on the fly helps make for a great way to modify your stylesheet in an iterative fashion.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:fa745c6d5d4149a498a59e7600da9c2a">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Building-an-XSL-Transform-Tool</comments>
      <itunes:summary>



&amp;nbsp;
Purpose of this tool is to apply the transformation in XSL on XML file and display the results.This tool is basically a Simple WinForm where the location of an XML file and a corresponding XSL file are specified.
 It then displays the results of the transformation in text box for review.



Michael K. Campbell


Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Studio Express Editions
Hardware: 
Download: 


C# Download

VB Download










A while back I got tired of looking for a simple solution to performing &#39;on the fly&#39;
XSL Transformations. I didn&#39;t want some memory-hog tool to completely isolate me from the details of the transform through layers of abstraction—just a light-weight tool that would act as a simple transformation engine. I just needed something to run
 a transform based on my stylesheet and let me quickly check the results in an iterative fashion. I looked for a while, and didn&#39;t find anything like that available. So I built my own simple solution. It wasn&#39;t much—just a simple WinForm where I could specify
 the location of an XML file and a corresponding XSL file and then push a button to fire the results of the transformation to a text box for review. While that worked fine, I recently decided that my home-grown solution needed a bit of a face-lift. Nothing
 dramatic. Just a few tweaks to make it easier to fine-tune my stylesheets on the fly.
 
A Glorified Text Editor
To keep things simple, I just wanted the added ability to edit my XML and XSL (mostly the latter) documents in the same tool that I used to transform them. I&#39;d been using either an open instance of Visual Studio to edit them (nice, but heavy), or NotePad.
 In a perfect world, I&#39;d get some of the key benefits of an editor like Visual Studio, but with the &amp;quot;weight&amp;quot; of something like NotePad. NotePad is actually fine for editing text files—only I hate the fact that it doesn&#39;t remember my tab position. In other words,
 if I&#39;ve &amp;quot;tab</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Building-an-XSL-Transform-Tool</link>
      <pubDate>Tue, 31 Oct 2006 15:46:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Building-an-XSL-Transform-Tool</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913470_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913470_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michael K. Campbell</dc:creator>
      <itunes:author>Michael K. Campbell</itunes:author>
      <slash:comments>4</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Building-an-XSL-Transform-Tool/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Harnessing the BackPack API - Part II</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This article is in series of BackPack API. The focus of this article is on another key consideration and needed component of the final application: local storage of BackPack data. This facilitates BackPack off-line,(need
 to operate against a local copy of a user's BackPack data.) If the application is online, the modification will be sent immediately; otherwise, the command will be shelved until the application regains an Internet connection and can pass the command up to
 the BackPack servers as needed.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Michael K. Campbell</div>
<div class="entry_company"><a href="http://www.angrypets.com/contact">Contact Michael K. Campbell</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Easy</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
3-6 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Studio Express Editions</a>,
<a href="http://www.backpackit.com/api/">BackPack API</a></span></div>
<div class="entry_details"><b>Hardware: </b><span class="entry_details_input"></span></div>
<div class="entry_details"><b>Download: </b>
<ul>
<li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/BackPackAPI_PartII-CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/BackPackAPI_PartII-VB.msi">VB Download</a></li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>One of the exciting new features of .NET 2.0 is the introduction of Generics: special template-like classes that allow developers to quickly and easily interact with collections of objects in an efficient, strongly-typed, manner. However, while a wealth
 of information can be found by searching the internet for articles and documentation on Generics, there's very little information available about the serialization of Generics into XML. In fact, documentation is virtually non-existent. This is too bad, because
 Generics lend themselves very well to serialization, and can really help make serializing collections of objects quite easy—once a few simple, but key, points are addressed. This article will take a look at some of those key points and provide some concrete
 examples of serializing Generics, as well as providing an overview of just how beneficial Generics are when it comes to serializing collections of objects.
</p>
<h4>The Back Pack API - Roadmap to our sample application </h4>
<p>In my previous article, I introduced the BackPack API and mentioned that I'd spend three articles looking into how to build a Winforms application that would not only allow for direct interaction with BackPackIt.com servers to manipulate user information,
 but that would also allow the data to be pulled down locally and manipulated off-line. In the previous article the focus was on providing an overview of BackPack, its accompanying API, and on writing code that dynamically generated XML data that represented
 user input which could then be sent back to the BackPack servers for processing. While the sample application in the previous article was a bit weak, it did cover some of the key concepts of dynamic XML generation with the DOM, and also showcased how easy
 it is to communicate with an 'XML' Web server—all of which were key components in building the final application which will be completed in the third installment of this series.
</p>
<p>The focus of this article will be on another key consideration and needed component of the final application: local storage of BackPack data. In order to facilitate being able to use BackPack off-line, the final application will need to operate against a
 local copy of a user's BackPack data. In the final application, when the user wants to change their data, the change will first be made against the local data store, and a corresponding modification will be sent for processing against the server. If the application
 is online, the modification will be sent immediately; otherwise, the command will be shelved until the application regains an Internet connection and can pass the command up to the BackPack servers as needed. The primary goal, therefore, will be to make BackPack
 &quot;portable&quot;—and XML will be a key player in making that so (and serializing Generics will play a large role in harnessing XML for our needs).
</p>
<p>Of course, until operations have been successfully completed on the server, we'll want some way to know that a local copy of a page is &quot;dirty&quot; or pending an update on the server. We'll also want to make sure that if something happens, and the modification
 can't be correctly executed on the server, that we'll have some way of recovering from such an issue. But we'll deal with all of those details in the next article. Here we'll focus on a framework that will allow us to save BackPack data locally so that it
 can be queried as needed—and serve as the basis for making changes against the server whether we're online or offline. In other words, the goal of this article will be to provide a few more key building blocks towards the final application in the form of a
 simple application that will allow us to: </p>
<ol>
<li>load pages from the server, </li><li>save them to disk, and then </li><li>load them from the server or from disk as needed. </li></ol>
<p><b>Architecture and Game Plan </b></p>
<p>The BackPack API returns data as XML. That's an excellent transport mechanism, but not something we want to work with in our final application. What we really want is the ability to interact with objects—to be able to tell them WHAT to do, and not have to
 worry about HOW that gets done. In other words, we want encapsulation: the ability to hide implementation details from other &quot;players&quot; in our application such that if the HOW needs to be changed, our application doesn't break. A quick review of the
<a href="http://www.backpackit.com/api/">BackPack API</a> shows that it provides a number of ways to access user data. For example, notes for a given page can be pulled back by querying a specific URL which will return an XML &quot;data-gram&quot; full of current notes
 associated with the requested page, as shown in the following screen capture taken from the API's documentation:
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/backpackapi_part2_1.gif" border="0">
</p>
<p>In other words, the API provides the ability to SLICE and DICE data—which is handy, but something our final application won't need. The goal of the final application will be to encapsulate EVERYTHING (well close to everything) available in the API, and,
 since the BackPack application revolves around pages, our application will also target pages. In other words, if we have a local copy of every page, we can then see which lists, notes, tags, links, etc. belong to any given page as needed—without requiring
 a bunch of chatty interactions with the server each time we need to know something. We'll therefore want to architect our application in such a way that it's
<b>page-centric</b>. As such, the general focus and flow of this article will be to:
</p>
<ol>
<li>Create a page-centric Object Model where interacting with a page provides us the ability to see assets (data) that belongs to said page, and (later, in article 3) modifying data belonging to the page is handled by the Page object itself.
</li><li>Construct the basis of a Business Object, or middle tier, that can manipulate page objects as needed—and can handle all of the gory details associated with bringing pages in and out of existence, whether from the server or from disk.
</li><li>Finally, we'll need to wrap the above functionality in a rudimentary GUI that will let us easily handle operations around loading and saving pages.
</li></ol>
<h4>Building the Object Model </h4>
<p>To build a suitable page-centric object model, we just need to gain an idea of what data points, or attributes, are found in each BackPack page, and create a corresponding data point, or property, for each in our classes. (In the third article we'll model
 behaviors, or methods that will allow us to modify and interact with page objects.) The quickest way to gain a sense of what data points need to be represented is to just take a look at a sample page documented in the API:
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/backpackapi_part2_2.gif" border="0">
</p>
<p>As I mentioned in the previous article, the BackPack API is well documented with good, solid, examples. This is true of the sample page covered in the API; it successfully models all of the data points potentially needed in a single page. Therefore, as you
 can see, a Page consists of an id, a title, a body, and potential collections of lists, notes, tags, etc. Modeling these last resource types is easy—and the logical place to start, as they are the constituent elements of any given page.
</p>
<p><b>NOTE:</b> Because a Generic Collection is frequently stored in a <b>System.Collections.Generic.List</b>, I've opted to call lists, in BackPack parlance, Tasks in my object model—just to make sure there won't be any confusion.
</p>
<p>A few seconds of typing in C# Express (using Code Snippets to generate the property definitions—woot!) and
<b>Links</b>, <b>Notes</b>, <b>Tags</b>, and <b>Tasks</b> have been quickly modeled (though the following image was generated in VS 2005):
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/backpackapi_part2_3.gif" border="0">
</p>
<p>Once these objects are defined, a <b>Page</b> object, which contains these data types as child nodes, can then be created in similar fashion. Like the classes above, it too consists of an
<b>id</b> property, along with a couple of other <code>string</code> fields, and then potential collections of the classes created above:
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/backpackapi_part2_4.gif" border="0">
</p>
<p>At this point, our object model is complete—at least from the standpoint of storing data at run time.
</p>
<h4>Let the Serialization Begin!</h4>
<p>With the object model in place, it's time to turn our attention to the process of translating our objects into XML and back out again to meet our persistence needs. For the final application, we'll need to &quot;create&quot; page objects from XML, whether they're
 being loaded from the BackPackIt.com servers or from the File System, where we've saved local copies to use when there is no connection to the Internet. Normally when basing objects off of XML provided by an outside party, it's a good idea to make sure that
 if the external party changes the XML, it doesn't break your application—or at least that such a change is easily dealt with. A good way to do that is to run the external XML through a transform that converts it to a dependable format used internally by your
 application. This can easily be done via an XML Transform, which can be thought of as a buffer interface designed to help abstract details of the foreign XML away from our application.
</p>
<p>Using a transform also provides another benefit: If we transform the incoming XML into the same format used by our application, then we can deserialize objects from BackPack servers and the file system using, effectively, the same functionality. In other
 words, a single page loaded from the server, once transformed, will look the same to our application as a collection of pages serialized to disk. And speaking of collections, that's where we need to turn our attention back to Generics. If you look at the implementation
 of the <b>Page</b> class, you'll see that the <b>Notes</b>, <b>Tasks</b>, <b>Tags</b>, and
<b>Links</b> are implemented as a Generic Type: <b>SerializableList</b>. That's a custom class that I've created especially for this application. The
<b>entire declaration</b> of that type is as follows: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode">[XmlType(<span class="str">&quot;{T}s&quot;</span>)]<br><span class="kwrd">public</span> <span class="kwrd">class</span> SerializableList&lt;T&gt; : List&lt;T&gt; { }    <br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code>
</code></pre>
<pre class="csharpcode">&lt;XmlType(<span class="str">&quot;{T}s&quot;</span>)&gt; _<br><span class="kwrd">Public</span> <span class="kwrd">Class</span> SerializableList(Of T)<br>    <span class="kwrd">Inherits</span> List(Of T)<br><span class="kwrd">End</span> Class</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Not a lot of code, is there? That's because a <b>SerializableList </b>is just a class that derives from the
<b>System.Collections.Generic.List</b> class (a container for Generics) that ships with the .NET Framework 2.0. Under the covers it behaves the exact same way as a
<b>List </b>object, but there's one subtle difference: this custom class has an <b>
XML Serialization</b> attribute that describes the type of information that will be serialized. That's what the
<code>[XMLType(&quot;{T}s&quot;]</code> denotes, where the <code>{T}</code> is a token used as a placeholder for the type of object held in the collection. Here's a conceptual view of how it would serialize in the wild:
</p>
<pre><code>&lt;{T}s&gt;<br>    &lt;TypeName&gt;data&lt;/TypeName&gt;<br>    &lt;TypeName&gt;data&lt;/TypeName&gt;<br>&lt;/{T}s&gt;<br></code></pre>
<p>Where the type of the object contained would be output as a parent element, denoted by the
<code>{T}</code> token, and then subsequent child elements would be serialized as needed. So, if the
<b>SerializableList</b> contained something simple, like a string (<code>SerializableList&lt;string&gt;</code>), the XML tags would look like:
</p>
<pre><code>&lt;strings&gt;<br>    &lt;string&gt;one&lt;/string&gt;<br>    &lt;string&gt;two&lt;/string&gt;<br>    &lt;string&gt;etc.&lt;/string&gt;<br>&lt;/strings&gt;<br></code></pre>
<p>See? Simple. Complex objects serialize the same way, making Generics a powerful ally in the serialization of collections. The only trick is coming up with an
<b>XmlTypeAttribute</b> name that is generic enough to describe whatever is being serialized; that way, one collection object will fit all of your serialization needs. In my case, I've just added an
<i>s</i> to the end of the type name itself, and called it good—but you could easily do something like add &quot;list&quot; to the end of yours and that would work equally well.
</p>
<p>So, with that bit of information covered, a <b>Page</b> object will then serialize, and any
<b>Tasks</b>, <b>Tags</b>, <b>Links</b>, or <b>Notes</b>, will serialize out as lists of the corresponding entities if any data is currently present. Here's an example:
</p>
<div class="body">
<div class="postBody" id="269f3ba4-1962-4c7b-9c62-d73b2d31a3b3">
<pre class="csharpcode"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> ?<span class="kwrd">&gt;</span><br><span class="kwrd">&lt;</span><span class="html">Pages</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;</span><span class="html">Page</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>Example Page<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>This page was created via the BackPack API.<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Tasks</span> <span class="kwrd">/&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Notes</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Note</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>Sample Note<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>This is the body of a note<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Id</span><span class="kwrd">&gt;</span>279762<span class="kwrd">&lt;/</span><span class="html">Id</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Created</span><span class="kwrd">&gt;</span>2005-09-29 15:08:08<span class="kwrd">&lt;/</span><span class="html">Created</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Note</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Note</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>Another Note<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>More body/sample<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Id</span><span class="kwrd">&gt;</span>279385<span class="kwrd">&lt;/</span><span class="html">Id</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Created</span><span class="kwrd">&gt;</span>2005-09-29 17:05:35<span class="kwrd">&lt;/</span><span class="html">Created</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Note</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;/</span><span class="html">Notes</span><span class="kwrd">&gt;</span>    <br>    <span class="kwrd">&lt;</span><span class="html">Links</span> <span class="kwrd">/&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Tags</span> <span class="kwrd">/&gt;</span><br><span class="kwrd">&lt;/</span><span class="html">Page</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style></div>
</div>
<pre><code></code></pre>
<p>Note how the collection of <b>Note</b> objects serialized as <code>&lt;Notes&gt;</code> (or
<code>&lt;{T}s&gt;</code> where the name of the type was a <b>Note</b>), and so on. What's more is that when we go to serialize a collection of
<b>Pages</b>, they too serialize the same way—as a <code>&lt;Pages&gt;</code> collection, with corresponding, nested, collections of their constituent data—making everything tidy and easy to handle.
</p>
<div class="body">
<div class="postBody" id="269f3ba4-1962-4c7b-9c62-d73b2d31a3b3">
<pre class="csharpcode"><span class="kwrd"></span><span class="kwrd"></span></pre>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Pages</span><span class="kwrd">&gt;</span><br> <span class="kwrd">&lt;</span><span class="html">Page</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>Example Page<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>This page was created via the BackPack API.<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tasks</span><span class="kwrd">&gt;</span><br>        <span class="rem">&lt;!-- elided from above --&gt;</span><br>   <span class="kwrd">&lt;/</span><span class="html">Tasks</span><span class="kwrd">&gt;</span>                <br>      <span class="kwrd">&lt;</span><span class="html">Links</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tags</span> <span class="kwrd">/&gt;</span><br> <span class="kwrd">&lt;/</span><span class="html">Page</span><span class="kwrd">&gt;</span><br> <span class="kwrd">&lt;</span><span class="html">Page</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>Another Page<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>This page doesn't have any data in it yet—other than title/body.<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tasks</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Notes</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Links</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tags</span> <span class="kwrd">/&gt;</span><br> <span class="kwrd">&lt;/</span><span class="html">Page</span><span class="kwrd">&gt;</span><br> <span class="kwrd">&lt;</span><span class="html">Page</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;</span>And Yet Another Page<span class="kwrd">&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;</span>Unlike the above page, this one has some data loaded...<span class="kwrd">&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tasks</span><span class="kwrd">&gt;</span><br>     <span class="kwrd">&lt;</span><span class="html">Task</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Text</span><span class="kwrd">&gt;</span>Get Stuff Done<span class="kwrd">&lt;/</span><span class="html">Text</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Id</span><span class="kwrd">&gt;</span>1347087<span class="kwrd">&lt;/</span><span class="html">Id</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Complete</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">Complete</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Task</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Task</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Text</span><span class="kwrd">&gt;</span>Do more stuff<span class="kwrd">&lt;/</span><span class="html">Text</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Id</span><span class="kwrd">&gt;</span>1347088<span class="kwrd">&lt;/</span><span class="html">Id</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">Complete</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">Complete</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Task</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;/</span><span class="html">Tasks</span><span class="kwrd">&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Notes</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Links</span> <span class="kwrd">/&gt;</span><br>      <span class="kwrd">&lt;</span><span class="html">Tags</span> <span class="kwrd">/&gt;</span><br> <span class="kwrd">&lt;/</span><span class="html">Page</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;/</span><span class="html">Pages</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style><style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style></div>
</div>
<pre><code></code></pre>
<p>Serializing objects is also terribly easy at this point as well. We just need to know the type of object to serialize (in this case a Generic Collection), a location to save the information, and an instance of the type of object to serialize that contains
 the data we need to serialize. Because we'll be serializing credentials and connection information, as well as pages (and later on even commands to modify data when offline), I've created a helper method as follows:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SerializeToFile(Type type, <span class="kwrd">object</span> data, <span class="kwrd">string</span> path, SavedFileType resourceType)<br>{<br>    <span class="kwrd">try</span>
    {
        XmlSerializer serializer = <span class="kwrd">new</span> XmlSerializer(type);<br>        XmlTextWriter tw = <span class="kwrd">new</span> XmlTextWriter(path, Encoding.UTF8);<br><br>        tw.Formatting = Formatting.Indented;<br>        tw.WriteRaw(<span class="str">&quot;&lt;?xml version=\&quot;1.0\&quot; ?&gt;&quot;</span>);<br><br>        XmlSerializerNamespaces ns = <span class="kwrd">new</span> XmlSerializerNamespaces();<br>        ns.Add(<span class="kwrd">string</span>.Empty, <span class="kwrd">string</span>.Empty);<br><br>        serializer.Serialize(tw, data, ns);<br>        tw.Close();<br><br>        <span class="kwrd">this</span>.OnSerializationComplete(<span class="kwrd">new</span> SerializationCompleteEventArgs(resourceType));<br>    }<br>    <span class="kwrd">catch</span> <span class="rem">// etc.. </span>
}
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SerializeToFile(<span class="kwrd">ByVal</span> type <span class="kwrd">As</span> Type, <span class="kwrd">ByVal</span> data <span class="kwrd">As</span> <span class="kwrd">Object</span>, <span class="kwrd">ByVal</span> path <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> resourceType <span class="kwrd">As</span> SavedFileType)<br><span class="kwrd">Try</span>
    <span class="kwrd">Dim</span> serializer <span class="kwrd">As</span> XmlSerializer = <span class="kwrd">New</span> XmlSerializer(type)<br>    <span class="kwrd">Dim</span> tw <span class="kwrd">As</span> XmlTextWriter = <span class="kwrd">New</span> XmlTextWriter(path, Encoding.UTF8)<br>    tw.Formatting = Formatting.Indented<br>    tw.WriteRaw(<span class="str">&quot;&lt;?xml version=&quot;</span><span class="str">&quot;1.0&quot;</span><span class="str">&quot; ?&gt;&quot;</span>)<br>    <span class="kwrd">Dim</span> ns <span class="kwrd">As</span> XmlSerializerNamespaces = <span class="kwrd">New</span> XmlSerializerNamespaces<br>    ns.Add(<span class="kwrd">String</span>.Empty, <span class="kwrd">String</span>.Empty)<br>    serializer.Serialize(tw, data, ns)<br>    tw.Close()<br><br>    <span class="kwrd">Me</span>.UpdateResourceStates(resourceType)<br><br>    <span class="kwrd">Me</span>.OnSerializationComplete(<br>        <span class="kwrd">New</span> SerializationCompleteEventArgs(resourceType))<br>    <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception<br>    <span class="kwrd">Throw</span> <span class="kwrd">New</span> NotImplementedException(<br>        <span class="str">&quot;Need to do a serialization exception..&quot;</span>, ex)<br>    <span class="kwrd">End</span> <span class="kwrd">Try</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>The code is pretty straightforward: it just creates an <b>XmlSerializer</b> instance of the type indicated, and contains a few snippets of code that replace the default XML Serialization namespaces (injected into the serialized XML) with null, or blank,
 namespaces which keep the serialized XML clean and tidy. </p>
<h4>Transforming incoming XML </h4>
<p>Now that we've seen what our pages look like once serialized, we can build a quick XSL transform to convert incoming BackPack XML into that same format so that we can deserialize BackPack pages from the server just as easily as those stored locally in our
 own format. The transform is a simple one, because both the BackPack XML and our own format are very element-heavy, which makes mapping really just a question of changing names from the incoming document to match the names of our objects.
</p>
<div class="body">
<div class="postBody" id="269f3ba4-1962-4c7b-9c62-d73b2d31a3b3">
<pre class="csharpcode"><span class="kwrd">&lt;?</span><span class="html">xml</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span>?<span class="kwrd">&gt;</span><br><span class="kwrd">&lt;</span><span class="html">xsl:stylesheet</span> <span class="attr">version</span><span class="kwrd">=&quot;1.0&quot;</span> <span class="attr">xmlns:xsl</span><span class="kwrd">=&quot;http://www.w3.org/1999/XSL/Transform&quot;</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;</span><span class="html">xsl:output</span> <span class="attr">method</span><span class="kwrd">=&quot;xml&quot;</span> <span class="kwrd">/&gt;</span><br><span class="kwrd">&lt;</span><span class="html">xsl:template</span> <span class="attr">match</span><span class="kwrd">=&quot;/&quot;</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Page</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span>false<span class="kwrd">&lt;/</span><span class="html">PageIsDirty</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Title</span><span class="kwrd">&gt;&lt;</span><span class="html">xsl:value-of</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/@title&quot;</span> <span class="kwrd">/&gt;&lt;/</span><span class="html">Title</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Body</span><span class="kwrd">&gt;&lt;</span><span class="html">xsl:value-of</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/description&quot;</span> <span class="kwrd">/&gt;&lt;/</span><span class="html">Body</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">xsl:if</span> <span class="attr">test</span>=&quot;<span class="attr">count</span>(<span class="attr">response</span>/<span class="attr">page</span>/<span class="attr">items</span>/*) <span class="kwrd">&gt;</span> 0&quot;<span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Tasks</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">xsl:apply-templates</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/items&quot;</span> <span class="kwrd">/&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Tasks</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">xsl:if</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">xsl:if</span> <span class="attr">test</span>=&quot;<span class="attr">count</span>(<span class="attr">response</span>/<span class="attr">page</span>/<span class="attr">notes</span>) <span class="kwrd">&gt;</span> 0&quot;<span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Notes</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">xsl:apply-templates</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/notes&quot;</span> <span class="kwrd">/&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Notes</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">xsl:if</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">xsl:if</span> <span class="attr">test</span>=&quot;<span class="attr">count</span>(<span class="attr">response</span>/<span class="attr">page</span>/<span class="attr">links</span>) <span class="kwrd">&gt;</span> 0&quot;<span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Links</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">xsl:apply-templates</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/links&quot;</span> <span class="kwrd">/&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Links</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">xsl:if</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">xsl:if</span> <span class="attr">test</span>=&quot;<span class="attr">count</span>(<span class="attr">response</span>/<span class="attr">page</span>/<span class="attr">tags</span>) <span class="kwrd">&gt;</span> 0&quot;<span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Tags</span><span class="kwrd">&gt;</span><br>            <span class="kwrd">&lt;</span><span class="html">xsl:apply-templates</span> <span class="attr">select</span><span class="kwrd">=&quot;response/page/tags&quot;</span> <span class="kwrd">/&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">Tags</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;/</span><span class="html">xsl:if</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;/</span><span class="html">Page</span><span class="kwrd">&gt;</span>    <br><span class="kwrd">&lt;/</span><span class="html">xsl:template</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;</span><span class="html">xsl:template</span> <span class="attr">match</span><span class="kwrd">=&quot;item&quot;</span><span class="kwrd">&gt;</span><br>    <span class="kwrd">&lt;</span><span class="html">Task</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Text</span><span class="kwrd">&gt;&lt;</span><span class="html">xsl:value-of</span> <span class="attr">select</span><span class="kwrd">=&quot;.&quot;</span> <span class="kwrd">/&gt;&lt;/</span><span class="html">Text</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Id</span><span class="kwrd">&gt;&lt;</span><span class="html">xsl:value-of</span> <span class="attr">select</span><span class="kwrd">=&quot;./@id&quot;</span> <span class="kwrd">/&gt;&lt;/</span><span class="html">Id</span><span class="kwrd">&gt;</span><br>        <span class="kwrd">&lt;</span><span class="html">Complete</span><span class="kwrd">&gt;&lt;</span><span class="html">xsl:value-of</span> <span class="attr">select</span><span class="kwrd">=&quot;./@completed&quot;</span> <span class="kwrd">/&gt;&lt;/</span><span class="html">Complete</span><span class="kwrd">&gt;</span><br> <span class="kwrd">&lt;/</span><span class="html">Task</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;/</span><span class="html">xsl:template</span><span class="kwrd">&gt;</span><br><span class="kwrd">&lt;!</span><span class="html">--</span> <span class="attr">elided</span> <span class="attr">for</span> <span class="attr">brevity</span> (<span class="attr">see</span> <span class="attr">sample</span> <span class="attr">code</span> <span class="attr">for</span> <span class="attr">more</span> <span class="attr">info</span>) <span class="attr">--</span> <span class="kwrd">&gt;</span><br><span class="kwrd">&lt;/</span><span class="html">xsl:stylesheet</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:Consolas,"Courier New",Courier,Monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style></div>
</div>
<pre><code></code></pre>
<p>I'm also a bit of a *cough* clean freak, so I've added a bit of logic to make sure that empty elements arriving from the server aren't included in our transformed XML—but that's a total waste of energy and cycles in case anyone was wondering (but serves
 as a simple example of how that could be done if you wanted your XML more human-readable).
</p>
<p>As for performing the transform, that will be done in memory as pages arrive from the server, as demonstrated by the following code:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> SinglePageReturned(<span class="kwrd">string</span> pageData)<br>{<br>    <span class="rem">// TODO: add try/catch etc</span>

    <span class="kwrd">byte</span>[] data = Encoding.UTF8.GetBytes(pageData);<br>    MemoryStream stream = <span class="kwrd">new</span> MemoryStream(data);<br>    XPathDocument input = <span class="kwrd">new</span> XPathDocument(stream);<br><br>    XslCompiledTransform xsl = <span class="kwrd">new</span> XslCompiledTransform();<br>    XmlNode stylesheet = <span class="kwrd">this</span>.LoadTransformDocument();<br>    xsl.Load(stylesheet);<br><br>    MemoryStream ms = <span class="kwrd">new</span> MemoryStream();<br>    StreamWriter sw = <span class="kwrd">new</span> StreamWriter(ms);<br><br>    xsl.Transform(input, <span class="kwrd">null</span>, sw);<br><br>    XmlDocument page = <span class="kwrd">new</span> XmlDocument();<br>    <span class="kwrd">byte</span>[] bytes = ms.ToArray();<br>    <span class="kwrd">string</span> transformedXml = Encoding.UTF8.GetString(bytes);<br>    page.LoadXml(transformedXml);<br>    sw.Dispose();<br>    ms.Close();<br>    ms.Dispose();<br><br>    XmlNode node = page.SelectSingleNode(<span class="str">&quot;/&quot;</span>);<br>    Page output = <span class="kwrd">this</span>.GetPageFromXml(node);<br><br>    <span class="kwrd">this</span>.AddPage(output);<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> SinglePageReturned(<span class="kwrd">ByVal</span> pageData <span class="kwrd">As</span> <span class="kwrd">String</span>)<br>        <span class="rem">' TODO: add try/catch etc</span>
        <span class="kwrd">Dim</span> data() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = Encoding.UTF8.GetBytes(pageData)<br>        <span class="kwrd">Dim</span> stream <span class="kwrd">As</span> MemoryStream = <span class="kwrd">New</span> MemoryStream(data)<br>        <span class="kwrd">Dim</span> input <span class="kwrd">As</span> XPathDocument = <span class="kwrd">New</span> XPathDocument(stream)<br>        <span class="kwrd">Dim</span> xsl <span class="kwrd">As</span> XslCompiledTransform = <span class="kwrd">New</span> XslCompiledTransform<br>        <span class="kwrd">Dim</span> stylesheet <span class="kwrd">As</span> XmlNode = <span class="kwrd">Me</span>.LoadTransformDocument<br>        xsl.Load(stylesheet)<br>        <span class="kwrd">Dim</span> ms <span class="kwrd">As</span> MemoryStream = <span class="kwrd">New</span> MemoryStream<br>        <span class="kwrd">Dim</span> sw <span class="kwrd">As</span> StreamWriter = <span class="kwrd">New</span> StreamWriter(ms)<br>        xsl.Transform(input, <span class="kwrd">Nothing</span>, sw)<br>        <span class="kwrd">Dim</span> page <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument<br>        <span class="kwrd">Dim</span> bytes() <span class="kwrd">As</span> <span class="kwrd">Byte</span> = ms.ToArray<br>        <span class="kwrd">Dim</span> transformedXml <span class="kwrd">As</span> <span class="kwrd">String</span> = Encoding.UTF8.GetString(bytes)<br>        page.LoadXml(transformedXml)<br>        sw.Dispose()<br>        ms.Close()<br>        ms.Dispose()<br>        <span class="kwrd">Dim</span> node <span class="kwrd">As</span> XmlNode = page.SelectSingleNode(<span class="str">&quot;/&quot;</span>)<br>        <span class="kwrd">Dim</span> output <span class="kwrd">As</span> Page = <span class="kwrd">Me</span>.GetPageFromXml(node)<br>        <span class="kwrd">Me</span>.AddPage(output)<br><span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note the helper method there that grabs the XSL file: <b>LoadTransformDocument()</b>. I've added that method as a helper to abstract the method used for grabbing the transform document listed above. In this sample application I'm grabbing that XSL document
 from the assembly itself. I did that ONLY to show that it can be done—which is a handy trick if you want to be able to load XSL transforms completely in memory and not require them to be dependent upon satellite files, etc.
<b>But in our case it doesn't really make the most sense as we're partially using the XSL document to shield us against changes to the incoming XML</b>—meaning that if 37Signals ever changed their XML format, we'd have to build a new transform, and then recompile
 our application to get the XSL document back into the Assembly's Resource Stream for further, continued, use in our application. So, with the caveat that I only did it this way to model how to pull XML documents out of your assembly, here's the code that fetches
 the XSL document: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> XmlNode LoadTransformDocument()<br>{<br>    <span class="kwrd">if</span> (<span class="kwrd">this</span>._stylesheetNode == <span class="kwrd">null</span>)<br>    {<br>        <span class="rem">// pull back the xslt document from the manifest:</span>
        Assembly current = Assembly.GetExecutingAssembly();
        XmlDocument doc = <span class="kwrd">new</span> XmlDocument();<br><br>        <span class="kwrd">using</span> (StreamReader sr = <span class="kwrd">new</span> StreamReader(current.GetManifestResourceStream(<span class="kwrd">this</span>.GetType(), <span class="str">&quot;transform.xsl&quot;</span>)))<br>            doc.Load(sr);<br><br>        XmlNode output = doc.SelectSingleNode(<span class="str">&quot;.&quot;</span>);<br>        <span class="kwrd">this</span>._stylesheetNode = output;<br>    }<br>    <span class="kwrd">return</span> <span class="kwrd">this</span>._stylesheetNode;<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code>
</code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> LoadTransformDocument() <span class="kwrd">As</span> XmlNode<br>    <span class="kwrd">If</span> (<span class="kwrd">Me</span>._stylesheetNode <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span>
    <span class="rem">' pull back the xslt document from the manifest:</span>
    <span class="kwrd">Dim</span> current <span class="kwrd">As</span> <span class="kwrd">Assembly</span> = <span class="kwrd">Assembly</span>.GetExecutingAssembly<br>    <span class="kwrd">Dim</span> doc <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument<br>    <span class="kwrd">Dim</span> sr <span class="kwrd">As</span> StreamReader = <br>        <span class="kwrd">New</span> StreamReader(current.GetManifestResourceStream(<br>        <span class="kwrd">Me</span>.<span class="kwrd">GetType</span>, <span class="str">&quot;transform.xsl&quot;</span>))<br>    doc.Load(sr)<br>    <span class="kwrd">Dim</span> output <span class="kwrd">As</span> XmlNode = doc.SelectSingleNode(<span class="str">&quot;.&quot;</span>)<br>    <span class="kwrd">Me</span>._stylesheetNode = output<br>    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">Return</span> <span class="kwrd">Me</span>._stylesheetNode<br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>In the final application, it would probably be better to just have this method open up a stream to the Current Directory where the application resides, and pull in a .xsl document—that way if the format ever needed to change, you could just replace the Transform
 document, and wouldn't need to recompile the app/bits. </p>
<h4>Translating Pages into Objects from XML </h4>
<p>With the transform built, and with a method to serialize pages to disk, we now just need to focus on pulling pages back from the BackPack server and turning them into objects. Then we can turn our attention to converting pages saved to disk back into objects
 as well. But, because the XML formats are the same, both operations will end up being quite similar—and are covered by the following two methods (one of which returns a single
<b>Page</b>, the other which returns a Collection, or <b>SerializableList</b>, of
<b>Page</b>s): </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> Page GetPageFromXml(XmlNode input)<br>{<br>    XmlSerializer s = <span class="kwrd">new</span> XmlSerializer(<span class="kwrd">typeof</span>(Page));<br>    Page page = (Page)s.Deserialize(<span class="kwrd">new</span> XmlNodeReader(input));<br><br>    <span class="kwrd">return</span> page;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> GetPageFromXml(<span class="kwrd">ByVal</span> input <span class="kwrd">As</span> XmlNode) <span class="kwrd">As</span> Page<br><span class="kwrd">Dim</span> s <span class="kwrd">As</span> XmlSerializer = <span class="kwrd">New</span> XmlSerializer(<span class="kwrd">GetType</span>(Page))<br><span class="kwrd">Dim</span> page <span class="kwrd">As</span> Page = <span class="kwrd">CType</span>(s.Deserialize(<span class="kwrd">New</span> XmlNodeReader(input)), Page)<br><span class="kwrd">Return</span> page<br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> SerializableList&lt;Page&gt; GetPagesFromXml(XmlNode input)<br>{<br>    XmlSerializer s = <span class="kwrd">new</span> XmlSerializer(<span class="kwrd">typeof</span>(SerializableList&lt;Page&gt;));<br>    SerializableList&lt;Page&gt; list =<br>        (SerializableList&lt;Page&gt;)s.Deserialize(<span class="kwrd">new</span> XmlNodeReader(input));<br><br>    <span class="kwrd">return</span> list;<br>}</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> GetPagesFromXml(<span class="kwrd">ByVal</span> input <span class="kwrd">As</span> XmlNode) <span class="kwrd">As</span>
   SerializableList(Of Page)
    <span class="kwrd">Dim</span> s <span class="kwrd">As</span> XmlSerializer = <span class="kwrd">New</span> XmlSerializer(<span class="kwrd">GetType</span>(<br>    SerializableList(Of Page)))<br>    <span class="kwrd">Dim</span> list <span class="kwrd">As</span> SerializableList(Of Page) = <span class="kwrd">CType</span>(s.Deserialize(<br>        <span class="kwrd">New</span> XmlNodeReader(input)), SerializableList(Of Page))<br>    <span class="kwrd">Return</span> list<br><span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Because the XML representing a BackPack page has been translated to the very format output by our serialized objects, hydration is a quick and simple operation. And, because our Generic
<b>SerializableList</b> has an XML Serialization attribute that lets it morph element names based upon the type of object collection being serialized, all of our nested objects line up perfectly and can therefore be hydrated and dehydrated as needed.
</p>
<h4>Loading Pages - Without Freezing the User Interface </h4>
<p>Many of the key components of the final application are now complete. We have a connection mechanism, created in the first article, that allows us to fetch XML from the BackPackIt.com servers, and we now have a mechanism in place that can turn XML into objects
 that can be used in our application. We also now have the ability to store those objects as a collection of
<b>Page</b>s on disk for use offline. All we really need at this point is to wire up existing functionality from the last article to request pages from the server so that they can be turned into objects that can be used by our application. We'll also need a
 user interface that will allow us to specify credentials, and direct operations—such as loading pages from the server (or from the file) as well as being able to save the pages to disk.
</p>
<p>In building the user interface, one thing we'll want to ensure is that we don't allow long-running interactions with the file system or remote servers to stall, or freeze the UI. To accomplish that, we'll need to implement those interactions asynchronously
 which will prevent locking the UI thread, and will avoid the possibility of collisions, or race conditions, from happening with data returned from either the remote server or the file system. Concurrent with our use of asynchronously invoking long running
 methods, we'll make use of events to &quot;announce&quot; the arrival of new pieces of data, and then handle binding that data to the user interface as needed. This will allow the Winform to be responsive while individual pages are being loaded from either the server
 or file system, and will further serve as the framework for the modification-oriented operations that we'll be working on in the next article.
</p>
<p><b>Asynchronous Architecture </b></p>
<p>To keep the application responsive, the user interface will route user requests into the business logic layer (the
<b>PageManager</b> object), where an asynchronous delegate will be used to perform the actual operation requested—leaving the UI thread free to stay focused on user interaction. Once the requested operation completes, it will raise in the
<b>PageManager</b> a <b>RemoteMethodComplete</b> event that will then be bubbled up and handled by the Winform. Handler logic associated with each event type will let the Winform process incoming information as needed, and the actual details of the operation
 itself (such an individual page) will be passed along in the event as part of a corresponding
<b>EventArgs</b> class accompanying each event. This will ensure that the state, or data, associated with the completion of each operation doesn't run the risk of getting overwritten by another operation completing concurrently (which was the case in the first
 example where I used a member variable to handle state data returned by the logging delegate).
</p>
<p>The actual invocation of any of the methods needed to request data from the BackPack servers will be routed through a helper method in the
<b>PageManager</b> that bundles up any needed XML, and the corresponding XML and places it implicitly on its own thread by &quot;scheduling&quot; the operation for completion by invoking it asynchronously on a delegate signature bound to the
<b>Connection</b> object: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> InvokeRemoteOperation(<span class="kwrd">string</span> url, XmlElement[] args)<br>{<br>    <span class="kwrd">if</span> (<span class="kwrd">this</span>._gateway.ConnectionInfo.IsOnline)<br>    {<br>        AsyncRemoteOperation operation = <span class="kwrd">new</span> AsyncRemoteOperation(<span class="kwrd">this</span>._gateway.ExecuteWebMethod);<br>        operation.BeginInvoke(url, args, <span class="kwrd">null</span>, <span class="kwrd">null</span>);<br>    }<br>    <span class="kwrd">else</span>
        <span class="rem">// covered in part III</span>
}
</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Overloads</span> <span class="kwrd">Sub</span> InvokeRemoteOperation(<span class="kwrd">ByVal</span> url <span class="kwrd">As</span> <span class="kwrd">String</span>, <br>    ByValargs() <span class="kwrd">As</span> XmlElement)<br><br>    <span class="kwrd">If</span> <span class="kwrd">Me</span>._gateway.ConnectionInfo.IsOnline <span class="kwrd">Then</span>
        <span class="kwrd">Dim</span> operation <span class="kwrd">As</span> AsyncRemoteOperation = <br>            <span class="kwrd">New</span> AsyncRemoteOperation(<br>            <span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>._gateway.ExecuteWebMethod)<br>        operation.BeginInvoke(url, args, <span class="kwrd">Nothing</span>, <span class="kwrd">Nothing</span>)<br>    <span class="kwrd">Else</span>
        <span class="rem">' covered in part III</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note too, that since this helper method serves to route all commands, it's the perfect place to either route the commands to the BackPack servers, or store the commands for later execution—which will be covered in the next article. As with the example from
 the last article, XML data is generated as needed, and passed in as an <b>XmlElement</b> array of
<code>args</code> that will be fired against the appropriate URL. But in the last article, the Winform was responsible for bundling up that data and preparing it. Logically, such interaction should be handled transparently by the Winform via the
<b>PageManager</b> class, which should know about how to handle the details of bundling XML and locating the correct URL, so that's how we'll do it in this article—by letting the PageManager handle all of those details. Once the XML is generated, and the URL
 is built, the PageManager routes the request into the <b>InvokeRemoteOperation()</b> method which asynchronously routes the commands into a
<b>BackPackGateway</b> object—a slight modification of the <b>BackPackRequest</b> class used in the previous article. The
<b>BackPackGateway</b> object handles the connection details, transfers data as needed, and once complete, raises an event which is then handled by the
<b>PageManager</b> which can evaluate the type of event raised, and determine what to do with the information returned:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> GatewayResponded(<span class="kwrd">object</span> sender, RemoteMethodCompleteEventArgs e)<br>{<br>    <span class="kwrd">if</span> (e.OperationStatus == CompletionStatus.Fail)<br>    {<br>        <span class="kwrd">throw</span> <span class="kwrd">new</span> BackPackServerException(<span class="str">&quot;Asynchronous BackPack Method Failed.&quot;</span>, e.Exception);<br>    }<br>    <span class="rem">// later: we'll parse the returned info much more fully, and handle it as</span>
    <span class="rem">//  appropriate - for now we just need to know if it was a single page, or a</span>
    <span class="rem">//  list of all the pages:</span>
    <span class="kwrd">if</span> (e.MethodUrl == <span class="str">&quot;/ws/pages/all&quot;</span>)<br>    {<br>        <span class="kwrd">this</span>.PagesListed(e.ResponseText);<br>    }<br>    <span class="kwrd">else</span> <span class="rem">// it's an individual page</span>
    {
        <span class="kwrd">this</span>.SinglePageReturned(e.ResponseText);<br>    }<br>}<br></pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> GatewayResponded(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> <span class="kwrd">Object</span>, <br>    <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> RemoteMethodCompleteEventArgs)<br>    <span class="kwrd">If</span> (e.OperationStatus = CompletionStatus.Fail) <span class="kwrd">Then</span>
        <span class="kwrd">Throw</span> <span class="kwrd">New</span> BackPackServerException(<br>        <span class="str">&quot;Asynchronous BackPack Method Failed.&quot;</span>, e.Exception)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="rem">' later: we'll parse the returned info much more fully, and handle it </span>
    <span class="rem">''as appropriate - for now we just need to know if it was a single </span>
    page, <span class="rem">'or a list of all the pages:</span>
    <span class="kwrd">If</span> (e.MethodUrl = <span class="str">&quot;/ws/pages/all&quot;</span>) <span class="kwrd">Then</span>
        <span class="kwrd">Me</span>.PagesListed(e.ResponseText)<br>    <span class="kwrd">Else</span>
        <span class="kwrd">Me</span>.SinglePageReturned(e.ResponseText)<br>    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode, .csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{background-color:#f4f4f4;
	width:100%;
	margin:0em}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>When the <b>PageManager</b> detects a list of pages being returned, it knows that those pages need to be loaded, and will therefore proceed to request each page in the collection on the current background thread. A URL is therefore built to handle the request,
 and routed into the <b>BackPackGateway</b> object, which will again bundle the request with user credentials, route the request to the appropriate URL on the BackPack server, process the response, and bundle the results into a corresponding
<b>RemoteMethodCompletedEventArgs</b> class which will be bubbled up to the PageManager via the
<b>RemoteMethodCompleted</b> Event. The <b>PageManager</b> will then again handle the event in the
<b>GatewayResonded</b> handler—only this time it will see that an individual page has been returned. The data from the event, XML representing the page, will be routed into a method that will transform the XML into our own persistence format, which will then
 translate the resultant XML into a full-blown <b>Page</b> object. Once the page is fully hydrated, the
<b>PageManager</b>, in turn, will add the page to its own internal collection of <b>
Page</b>s, and will then bundle the page into a <b>PageAddedEventArgs</b> class, and announce the arrival of the new page to the Winform via the
<b>PageAdded</b> event. The Winform, which has been sitting around waiting for user input (or notification from back end processes), will handle the
<b>PageAdded</b> event and will, in this article, respond by binding the <b>Page</b>'s title to the
<b>TreeView</b> control used to represent our <b>Page</b> objects: </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/BackPackAPI_Part2_5.gif"><img alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913408/BackPackAPI_Part2_5_thumb.gif" border="0"></a>
</p>
<p><b>(click image to zoom)</b> </p>
<p>In this way, the actions required to load the pages take place transparently under the covers, and the pages just appear in the UI once they are fully loaded and announced to the Winform by backend logic and processing. Once the pages are fully loaded from
 the server, the UI will toggle a Pages Menu Item command that will let us save pages to disk—which can be accomplished by simply sending the
<b>PageManager</b>'s internal collection of <b>Page </b>objects to the serialization helper method that we created earlier (<b>SerializeToFile()</b>).
</p>
<p>Once the pages are saved to disk, they can then be loaded from disk, in much the same way as they are loaded from the server: an asynchronous delegate will open up a stream to the persisted XML, and will then hand that off to the
<b>GetPagesFromXml()</b> helper method, which will return a <b>SerializableList</b> of
<b>Page</b>s. This Generic Collection of <b>Page</b>s can then be assigned to the
<b>PageManager</b>'s internal collection of <b>Page</b>s, and each page can be announced to the Winform by bundling it up in a
<b>PageAddedEventArg</b> and bubbling it up to the Winform via the <b>PageAdded</b> event such that it can then be bound to the Winform's
<b>TreeView</b> control in the same manner as individual pages were bound as they arrived from the BackPack server.
</p>
<h4>Wrapping it all up </h4>
<p>We're now, effectively, feature-complete for this article: we have the ability to 1) load pages from the server, 2) save them to disk, and then 3) reload them from disk. To the application, specifically the Winform, there's really no difference between pages
 loaded from the server and those loaded from disk—they're just objects which were once expressed as XML. In the next article we'll look at interacting with those objects, and marshalling changes made to them back and forth between our application and the BackPack
 servers. If the application is offline, then the commands to modify the data will be persisted locally as XML which can be re-hydrated and sent to the server once the application regains an Internet connection. Once the modification against the server is complete,
 an event will be raised by the <b>BackPackGateway</b>, processed by the <b>PageManager</b>, and announced to the Winform as needed—be it a success or a failure.
</p>
<p><b>Now, if you've made it this far, there's some homework:</b> go take a look at the sample code. Note that the helper method used to serialize pages to disk has also been used for serializing credentials, which can now be serialized to disk as well—making
 it so that you don't need to keep pasting in the API Key each time you fire off the application for testing and debugging. Check out the event model, and how it allows us to keep data channels clear, and free from potential collisions, or race conditions that
 would otherwise occur if we were using shared variables between multiple, concurrent threads. Then take the application for a test ride, and watch how responsive it is as long-running applications take place in the background—something that will be a key consideration
 when we change data in the next article: the data will be flagged as changed locally, and once completed/committed on the server, an event will be raised locally which will un-flag a particular data point as being dirty. And the cool thing? This will happen
 whether we're online or offline, making it possible for us visually to keep an eye on nodes that have been altered while our BackPack is offline.
</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:05ec87ad83784b22be859e7600daa4ca">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-II</comments>
      <itunes:summary>



&amp;nbsp;
This article is in series of BackPack API. The focus of this article is on another key consideration and needed component of the final application: local storage of BackPack data. This facilitates BackPack off-line,(need
 to operate against a local copy of a user&#39;s BackPack data.) If the application is online, the modification will be sent immediately; otherwise, the command will be shelved until the application regains an Internet connection and can pass the command up to
 the BackPack servers as needed.



Michael K. Campbell
Contact Michael K. Campbell

Difficulty: Easy
Time Required: 
3-6 hours
Cost: Free
Software: Visual Studio Express Editions,
BackPack API
Hardware: 
Download: 

C# Download
VB Download






One of the exciting new features of .NET 2.0 is the introduction of Generics: special template-like classes that allow developers to quickly and easily interact with collections of objects in an efficient, strongly-typed, manner. However, while a wealth
 of information can be found by searching the internet for articles and documentation on Generics, there&#39;s very little information available about the serialization of Generics into XML. In fact, documentation is virtually non-existent. This is too bad, because
 Generics lend themselves very well to serialization, and can really help make serializing collections of objects quite easy—once a few simple, but key, points are addressed. This article will take a look at some of those key points and provide some concrete
 examples of serializing Generics, as well as providing an overview of just how beneficial Generics are when it comes to serializing collections of objects.
 
The Back Pack API - Roadmap to our sample application 
In my previous article, I introduced the BackPack API and mentioned that I&#39;d spend three articles looking into how to build a Winforms application that would not only allow for direct interaction with BackPackIt.com servers to manipulate user information,
 but that would als</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-II</link>
      <pubDate>Tue, 31 Oct 2006 15:43:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-II</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913408_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913408_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michael K. Campbell</dc:creator>
      <itunes:author>Michael K. Campbell</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-II/RSS</wfw:commentRss>
    </item>
  <item>
      <title>Harnessing the BackPack API - Part I</title>
      <description><![CDATA[<span id="c4fmetadata">
<table class="" cellspacing="0" cellpadding="1" width="100%" border="0">
<tbody>
<tr class="entry_overview">
<td class="" width="50">&nbsp;</td>
<td class=""><span class="entry_description">This article discusses how to set up a free BackPack account, grab the XML Token needed to interact with the BackPack web service, and delve into connecting to the server to send commands and data back and forth.</span></td>
</tr>
<tr>
<td class="" colspan="2">
<div class="entry_author">Michael K. Campbell</div>
<div class="entry_company"><a href="http://blogs.msdn.com/controlpanel/blogs/"></a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Intermediate</span></div>
<div class="entry_details"><b>Time Required:</b> <span class="entry_details_input">
1-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Studio Express Editions</a>,
<a href="http://www.backpackit.com/api/">BackPack API</a></span></div>
<div class="entry_details"><b>Hardware: </b></div>
<div class="entry_details"><strong>Download:</strong></div>
<ul>
<li>
<div class="entry_details"><a class="" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_CS.msi">C# Download</a></div>
</li><li>
<div class="entry_details"><a class="" href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_VB.msi">VB Download</a></div>
</li></ul>
<div class="entry_details">
<ul>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<p>&nbsp;</p>
<p>In the &quot;old days&quot; there was a debate that raged between Palm and Windows CE zealots. The focus of the debate was a question of whether Palm, with its simple OS and simple functionality, was better suited to meeting users needs, or whether Windows CE, with
 all of its complex functionality, provided a better option. In simplest terms, the argument was really a question of which was more. Was more more, or was less more? I was always of the impression that more was more—at least in that debate.
</p>
<p>But sometimes less can definitely be more. Enter a small company made up of five individuals that understands this very well:
<a href="http://www.37signals.com/">37 Signals</a>. They've successfully launched three VERY SIMPLE online applications that have made them nearly legendary in the web development community. The secret of their success: carefully targeted applications that
 leverage cutting-edge technology to make collaboration intuitive through absurdly clean and simple user interfaces that anyone can quickly and easily use. Couple those strengths with a &quot;first hit is free&quot; marketing model to compel users to upgrade to paid
 services for improved productivity, and it's not hard to see why they've done so well.
</p>
<h4>Glad you like the 37 Signals Kool-Aid, but I thought this was an article about XML?</h4>
<p>One of the great things about XML is that it is close to becoming ubiquitous. It really is becoming the lingua franca of data transfer. (There's still an inordinate amount of delimited, flat-file, legacy, evil out there in the corporate universe, though.)
 37 Signals obviously appreciates the inherent benefits of XML as a data exchange mechanism, and has therefore provided an easy-to-use API that allows users to interact with one of their core products: BackPack.
</p>
<p>BackPack is definitely a &quot;less is more&quot; application. It can be used solely by individuals, but it truly shines when used by small groups for effective collaboration. The best way to summarize it is to think of it in terms of being a terribly streamlined
<a href="http://en.wikipedia.org/wiki/Wiki">wiki</a>—one that's so easy to use that even pointy-haired bosses would feel at home slicing and dicing with it. It's successful because it really doesn't need much in the way of explanation; the user interface nimbly
 guides users along to being able to quickly and deftly master the product—all without realizing that they've strayed into something as geeky as a wiki because the user interface does such a great job of shielding the user from all of the underlying complexity.
 And in many ways, that same simplicity is carried over very well into the XML API.
</p>
<h4>XML4Fun and the BackPack API</h4>
<p>So, over the next three articles we're going to take a look at the BackPack API and put it to use for our own amusement. In the first article we'll quickly cover how to set up a free BackPack account, grab the XML Token needed to interact with the BackPack
 web service, and delve into connecting to the server to send commands and data back and forth. We'll do this by building a very rough and tumble Windows Forms application that models all of the available operations for just the BackPack page object. In the
 next two articles we'll quickly flesh out the rest of the API, improve the UI for our application, and then play around with XML serialization and other goodness to make our BackPack portable—in the sense that we'll pimp out the sample app for use when we're
 offline by making it capable of caching data and queuing changes/commands. </p>
<h5>Creating an account</h5>
<p>In order to play around with the API, you'll need to set up an account. Basic accounts are
<a href="http://123.backpackit.com/signup">free and easy to set up</a>. Once you register for your free account, you'll want to zip into your account details and grab your service token—a SHA1 security token that identifies you to the BackPack Service. Your
 service token is found at the bottom of your account page: </p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_parti_1.gif" border="0">
</p>
<h5>The API</h5>
<p>The API is <a href="http://www.backpackit.com/api/">well documented</a> with excellent examples on the BackPack site. The introduction to the API defines the interchange requirements (more on those in a second), and presents a bevy of examples showing both
 the posted data, and the corresponding response. It's an API that teaches through examples—and one that doesn't cut corners, which is usually quite rare.
</p>
<p>The thing I just love about this API is the sheer simplicity of it. It reminds me of what I like to call the poor man's web service (web services too old or too poor to use SOAP). Lots of these &quot;services&quot; existed back in the day before SOAP became all the
 rage, and they were almost invariably just clients and servers shooting XML packages back and forth to each other. Only those &quot;'services&quot; were usually horribly documented, and hacked together with franken-logic that made them hard to understand. The BackPack
 API, on the other hand, is very cut-and-dried and logically constrained. Small XML packages are sent up to logically defined URLs on the server for each &quot;method,&quot; and packets of XML &quot;data&quot; are sent back down for consumption.
</p>
<h4>Creating a Communication Mechanism</h4>
<p>Once you've had a moment to scroll through the API documentation and get a good feel for it, it's time to address the creation of a communication mechanism between our client and the BackPack Service. Fortunately, .NET makes this kind of interaction brutally
 simple by providing the <b>System.Net.HttpWebRequest</b>, and corresponding <b>System.Net.HttpWebResponse</b> objects. All we need to do is add a bit of &quot;decoration&quot; to a standard POST screen-scrape, and we be flipping XML back and forth in no time.
</p>
<p>The BackPack API specifies that we need to include a custom request header:<b> X-POST_DATA_FORMAT</b> (set to the value of &quot;xml&quot;) in order to have our requests properly identified on the server. For good measure I also always like to specify the MIME Type
 wherever possible, which I've done as well: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode">HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = <span class="str">&quot;POST&quot;</span>;
request.Headers.Add(<span class="str">&quot;X-POST_DATA_FORMAT&quot;</span>, <span class="str">&quot;xml&quot;</span>);
request.ContentType = <span class="str">&quot;application/xml&quot;</span>;

<span class="rem">// won't work: needs to be encoded:</span>
request.ContentLength = xml.Length;
StreamWriter post = <span class="kwrd">new</span> StreamWriter(request.GetRequestStream());
post.Write(xml);
post.Close();

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

StreamReader responseBody = <span class="kwrd">new</span> StreamReader(response.GetResponseStream());
<span class="kwrd">string</span> responseInfo = responseBody.ReadToEnd();
responseBody.Close();</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code><br>
</code></p>
<pre class="csharpcode"><span class="kwrd">Dim</span> request <span class="kwrd">As</span> HttpWebRequest = <span class="kwrd">CType</span>(WebRequest.Create(url), HttpWebRequest)

request.Method = <span class="str">&quot;POST&quot;</span>
request.Headers.Add(<span class="str">&quot;X-POST_DATA_FORMAT&quot;</span>, <span class="str">&quot;xml&quot;</span>)
request.ContentType = <span class="str">&quot;application/xml&quot;</span>

<span class="rem">' won't work: needs to be encoded:</span>
request.ContentLength = xml.Length
<span class="kwrd">Dim</span> post <span class="kwrd">As</span> StreamWriter = <span class="kwrd">New</span> StreamWriter(request.GetRequestStream())
post.Write(xml)
post.Close()

<span class="kwrd">Dim</span> response <span class="kwrd">As</span> HttpWebResponse = <span class="kwrd">CType</span>(request.GetResponse(), HttpWebResponse)

<span class="kwrd">Dim</span> responseBody <span class="kwrd">As</span> StreamReader = <span class="kwrd">New</span> 
    StreamReader(response.GetResponseStream())
<span class="kwrd">Dim</span> responseInfo <span class="kwrd">As</span> <span class="kwrd">String</span> = responseBody.ReadToEnd()
responseBody.Close()</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>And that's about it. An <b>HttpWebRequest</b> abstracts away all the gory socket details, and the response, if everything works out correctly, is returned to a simple string that can easily be consumed as needed.
</p>
<h4>Building an Application to Interact with the API</h4>
<p>Once we've got a suitable chunk of communication code, we can build an application around it. I'm using Visual C# Express, which makes creating and laying out form controls very simple. Since stubbing out code for an API usually involves lots of semi-repetitive
 copy/paste/tweak activities, typos are probably going to abound. That, and just to make this sample application cooler, I'm going to provide a simple way to view the XML sent up as well as the XML sent back down. Real estate for that will cover a large section
 of the sample app. Not only will this will help make debugging easier, it will provide a window on what is taking place from an XML standpoint as the gears churn inside our app.
</p>
<p>In this first article we'll only be covering Page operations (we'll cover Notes, Tags, Reminders, etc. in the next article), but I'll still need a way to display a running list of pages from which we can pick targets to update, delete, display, etc. So we'll
 need a list box to house a list of available pages, and another section of the Winform dedicated to implementing the Page operations outlined by the API. Finally, we'll need a way to specify which account to connect to, along with a way to provide our API
 Key for inclusion during requests. </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_2.gif"><img alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_2_thumb.gif" border="0"></a>
</p>
<p><b>(click image to zoom)</b> </p>
<p>As you can see, the choice of which API method to invoke is controlled through a simple radio button—with the exception of the
<b>List All</b> method—which is bound to the Load Pages button (which makes more sense). A couple of text boxes and a check box are then laid off to the side of the radio buttons for use in collecting user input, and fields are toggled on and off as needed,
 depending upon which radio button is selected. (Something tells me that 37 Signals' UI is a tad better than mine.)
</p>
<h5>Constructing the XML</h5>
<p>Of course, pushing buttons, no matter how elegantly (or horribly) laid out on a Winform, doesn't do much for an application that needs to communicate with a server in XML. Again, because of how simple the API is, and because the XML is also very simple,
 using the XML Document Object Model (DOM) is the perfect choice to generate suitable XML to translate user input where needed.
</p>
<p>Working with the DOM is quite fun when it comes to generating new XML. The basic idea is that with an XML Document loaded (even a blank one) you can &quot;float&quot; new XML Elements (or other nodes, e.g. comments, attributes, etc.) off of the root of the document,
 meddle with the node's internal data, and then append that node to a selected location somewhere specific within the document. If you've done this before, it's second nature; but learning how it all takes place can be a bit of a mind-bender for many people.
 Within the .NET Framework, the DOM is abstracted into the <b>System.Xml.XmlDocument</b> object, which provides all of the needed functionality to create new elements, populate them with content, and then to arrange them as desired.
</p>
<p>For example, to create a new page, the API indicates that we need to have two child elements (title and description), nested into the page element. The following code shows how a blank
<b>XmlDocument</b> instance is used to create three new elements programmatically. When these elements are created, they're out in limbo—just sticking off of the
<b>XmlDocument</b> like hideous extraneous appendages. It's not until they are ordered and arranged that they take the shape that we want:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode">XmlDocument args = <span class="kwrd">new</span> XmlDocument();
XmlElement page = args.CreateElement(<span class="str">&quot;page&quot;</span>);
XmlElement title = args.CreateElement(<span class="str">&quot;title&quot;</span>);
title.InnerText = <span class="kwrd">this</span>.txtPageTitle.Text.Trim();
XmlElement description = args.CreateElement(<span class="str">&quot;description&quot;</span>);
description.InnerText = <span class="kwrd">this</span>.txtPageBody.Text.Trim();

page.AppendChild(title);
page.AppendChild(description);</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Dim</span> args <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument()
<span class="kwrd">Dim</span> page <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;page&quot;</span>)
<span class="kwrd">Dim</span> title <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;title&quot;</span>)
title.InnerText = <span class="kwrd">Me</span>.txtPageTitle.Text.Trim()
<span class="kwrd">Dim</span> description <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;description&quot;</span>)
description.InnerText = <span class="kwrd">Me</span>.txtPageBody.Text.Trim()

page.AppendChild(title)
page.AppendChild(description)</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Pretty simple, isn't it? With that little bit of code we've created the XML necessary for interaction with the API.
</p>
<h5>Herding Ducks—or How to Wrap an API</h5>
<p>With connectivity and XML manipulation logic in place, as well as a Winform to handle user input and interaction, it's time to figure out the best way to wrap the BackPack API. Any time you wrap an API, you are invariably embedding oodles of logic into your
 code, and one of the key goals is to do so without repetition—which makes code harder to maintain. The other goal is to make sure that you don't end up making your logic too aware of itself to the point where code in region
<i>x</i> KNOWS how code in section <i>y</i> should behave, and comes to rely upon that anticipated behavior. Making that mistake is the sin of poor coupling, and can result in shame, ruin, and discredit to you and your children's children's children.
</p>
<p>One of the key things I wanted to accomplish in my effort to wrap the API was to keep as much of the core logic as close together as possible without adding lots of &quot;logic-bloat&quot; around one of the core pieces of the API—manipulation of the URLs that effectively
 act as the method names. These &quot;method names&quot; needed to be dynamically selected based on the user action, but from there, similarity between the methods effectively breaks down. This is where Delegates come in. Using Delegates allowed me to keep all of the
 URL-building-goodness localized to one single routine: an event handler for the Submit button. Here all of the URLs could be easily mapped and dynamically created (if needed), and comparatively complex logic such as building XML-grams of various types of user
 data could be handled in subsequent &quot;starting point&quot; methods as required. </p>
<p>But Delegates also bring something else to the table. Winforms that spend time communicating with various off-box server endpoints are subject to &quot;freezing up&quot; while communication is underway unless a background thread is directed to handle the communication—leaving
 the main Winform thread free to handle UI tasks. Using Delegates allows for a clean and easy way to spawn new background threads that can handle implementation details such as gathering user input, bundling it up, and then invoking the proper web method—all
 while leaving the Winform's main thread open to handle the message pump and UI tasks. Here's a code snippet of the entire event handler for the Submit button, where the URL is constructed as needed, a Delegate is wired up with the correct handling routine,
 and a thread is started to handle the communication: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> button2_Click(<span class="kwrd">object</span> sender, EventArgs e)
{
    <span class="rem">// everything except for creating a new page requires a pageID:</span>
    <span class="kwrd">if</span> (<span class="kwrd">this</span>._currentOperation != PageOperation.Create)
    {
        <span class="kwrd">if</span> (<span class="kwrd">this</span>._currentPageId == 0)
        {
            MessageBox.Show(<span class="str">&quot;Please Select a Page First.&quot;</span>);
            <span class="kwrd">return</span>;
        }
    }

    <span class="rem">// specify the path to connect to on the backpack server, and call appropriate methods</span>
    <span class="rem">//</span>
        to load xml <span class="str">'args'</span> <span class="kwrd">as</span> needed:
    OperationDelegate operation = <span class="kwrd">null</span>;
    <span class="kwrd">switch</span> (<span class="kwrd">this</span>._currentOperation)
    {
        <span class="rem">//case PageOperation.ListAll:</span>
        <span class="rem">//    break;</span>
        <span class="kwrd">case</span> PageOperation.Create:
            <span class="kwrd">this</span>._webMethodPath = <span class="str">&quot;/ws/pages/new&quot;</span>;
            operation = <span class="kwrd">new</span> OperationDelegate(<span class="kwrd">this</span>.InvokeCreatePage);
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> PageOperation.Show:
            <span class="kwrd">this</span>._webMethodPath = <span class="kwrd">string</span>.Format(<span class="str">&quot;/ws/page/{0}/show&quot;</span>, 
                <span class="kwrd">this</span>._currentPageId.ToString());
            operation = <span class="kwrd">new</span> OperationDelegate(<span class="kwrd">this</span>.InvokeSimpleMethod);
            <span class="kwrd">break</span>;
        <span class="kwrd">case</span> PageOperation.Destroy:
            <span class="kwrd">this</span>._webMethodPath = <span class="kwrd">string</span>.Format(<span class="str">&quot;/ws/page/{0}/destroy&quot;</span>, 
                <span class="kwrd">this</span>._currentPageId.ToString());
            operation = <span class="kwrd">new</span> OperationDelegate(<span class="kwrd">this</span>.InvokeSimpleMethod);
            <span class="kwrd">break</span>;

    <span class="rem">// elided for brevity... </span>
    
        <span class="kwrd">case</span> PageOperation.Email:
            <span class="kwrd">this</span>._webMethodPath = <span class="kwrd">string</span>.Format(<span class="str">&quot;/ws/page/{0}/email&quot;</span>, 
                <span class="kwrd">this</span>._currentPageId.ToString());
            operation = <span class="kwrd">new</span> OperationDelegate(<span class="kwrd">this</span>.InvokeSimpleMethod);
            <span class="kwrd">break</span>;
        <span class="kwrd">default</span>:
            MessageBox.Show(<span class="str">&quot;Woops.&quot;</span>);
            <span class="kwrd">break</span>;
    }

    <span class="kwrd">if</span> (operation != <span class="kwrd">null</span>)
    {
        Thread operationHandler = <span class="kwrd">new</span> Thread(<span class="kwrd">new</span> ThreadStart(operation));
        operationHandler.IsBackground = <span class="kwrd">true</span>;
        operationHandler.Start();
    }
}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> Button2_Click(<span class="kwrd">ByVal</span> sender <span class="kwrd">As</span> System.<span class="kwrd">Object</span>, 
    <span class="kwrd">ByVal</span> e <span class="kwrd">As</span> System.EventArgs) <span class="kwrd">Handles</span> Button2.Click
    <span class="kwrd">If</span> <span class="kwrd">Me</span>._request <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        MessageBox.Show(<span class="str">&quot;Please enter your credentials first.&quot;</span>)
        <span class="kwrd">Return</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">If</span> <span class="kwrd">Me</span>._currentOperation &lt;&gt; PageOperation.Create <span class="kwrd">Then</span>
        <span class="kwrd">If</span> <span class="kwrd">Me</span>._currentPageId = 0 <span class="kwrd">Then</span>
            MessageBox.Show(<span class="str">&quot;Please Select a Page First.&quot;</span>)
            <span class="kwrd">Return</span>
        <span class="kwrd">End</span> <span class="kwrd">If</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>


    <span class="rem">' specify the path to connect to on the backpack server, and call </span>
    <span class="rem">'appropriate methods</span>
    <span class="rem">'to load xml 'args' as needed:</span>

    <span class="rem">' vb.net doesn't play nicely with delegates... so the vb.net version </span>
    <span class="rem">'will create a different threadstart in each</span>
    <span class="rem">'   case:</span>
    <span class="kwrd">Dim</span> ts <span class="kwrd">As</span> ThreadStart = <span class="kwrd">Nothing</span>
    <span class="kwrd">Select</span> <span class="kwrd">Case</span> <span class="kwrd">Me</span>._currentOperation
        <span class="rem">'case PageOperation.ListAll:</span>
        <span class="rem">'    break;</span>
        <span class="kwrd">Case</span> PageOperation.Create
            <span class="kwrd">Me</span>._webMethodPath = <span class="str">&quot;/ws/pages/new&quot;</span>
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeCreatePage)
        <span class="kwrd">Case</span> PageOperation.Show
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/show&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSimpleMethod)
        <span class="kwrd">Case</span> PageOperation.Destroy
                <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/destroy&quot;</span>,
                    <span class="kwrd">Me</span>._currentPageId.ToString())
                ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSimpleMethod)
        <span class="kwrd">Case</span> PageOperation.UpdateTitle
                <span class="kwrd">Me</span>._webMethodPath = 
                    <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/update_title&quot;</span>, 
                    <span class="kwrd">Me</span>._currentPageId.ToString())
                ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeUpdateTitle)
        <span class="kwrd">Case</span> PageOperation.UpdateDescription
                <span class="kwrd">Me</span>._webMethodPath = 
                    <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/update_body&quot;</span>, 
                    <span class="kwrd">Me</span>._currentPageId.ToString())
                ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeUpdateDescription)
        <span class="kwrd">Case</span> PageOperation.Duplicate
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/duplicate&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSimpleMethod)
        <span class="kwrd">Case</span> PageOperation.Link
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/link&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokePageLinkManagment)
        <span class="kwrd">Case</span> PageOperation.Unlink
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/unlink&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokePageLinkManagment)
        <span class="kwrd">Case</span> PageOperation.Share
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/share&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSharePage)
        <span class="kwrd">Case</span> PageOperation.Unshare
            <span class="rem">' NOTE: Though this doesn't return an error, it doesn't seem </span>
            <span class="rem">'to do ANYTHING in terms of sharing. </span>
            <span class="rem">' So the API/docs are either in error, or I don't understand </span>
            <span class="rem">'what we're trying to do here (most likely).</span>
            <span class="kwrd">Me</span>._webMethodPath = 
                <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/unshare_friend_page&quot;</span>,
                    <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSimpleMethod)
        <span class="kwrd">Case</span> PageOperation.Email
            <span class="kwrd">Me</span>._webMethodPath = <span class="kwrd">String</span>.Format(<span class="str">&quot;/ws/page/{0}/email&quot;</span>, 
                <span class="kwrd">Me</span>._currentPageId.ToString())
            ts = <span class="kwrd">New</span> ThreadStart(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.InvokeSimpleMethod)
        <span class="kwrd">Case</span> <span class="kwrd">Else</span>
            MessageBox.Show(<span class="str">&quot;Woops.&quot;</span>)
    <span class="kwrd">End</span> <span class="kwrd">Select</span>

    <span class="kwrd">If</span> (ts &lt;&gt; <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span>
        <span class="rem">' vb doesn't do delegates the same way as the c# code:</span>
        <span class="kwrd">Dim</span> operationHandler <span class="kwrd">As</span> Thread = <span class="kwrd">New</span> Thread(ts)
        operationHandler.IsBackground = <span class="kwrd">True</span>
        operationHandler.Start()
    <span class="kwrd">End</span> <span class="kwrd">If</span>
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Now, I've managed to keep all of my URLs in one tidy location, without a ton of code crammed into each case, to help improve readability. Instead, Delegates allow the complex logic to be handled in a suitable method that will be started on another thread.
 For example, the creation of a page, which requires additional XML arguments to be assembled, is handled like so:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> InvokeCreatePage()
{
    XmlDocument args = <span class="kwrd">new</span> XmlDocument();
    XmlElement page = args.CreateElement(<span class="str">&quot;page&quot;</span>);
    XmlElement title = args.CreateElement(<span class="str">&quot;title&quot;</span>);
    title.InnerText = <span class="kwrd">this</span>.txtPageTitle.Text.Trim();
    XmlElement description = args.CreateElement(<span class="str">&quot;description&quot;</span>);
    description.InnerText = <span class="kwrd">this</span>.txtPageBody.Text.Trim();

    page.AppendChild(title);
    page.AppendChild(description);

    <span class="kwrd">this</span>._request.ExecuteWebMethod(<span class="kwrd">this</span>._webMethodPath, page);
}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b><code><br>
</code></p>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> InvokeCreatePage()
    <span class="kwrd">If</span> <span class="kwrd">Me</span>.txtPageTitle.Text.Length &lt; 1 <span class="kwrd">Or</span> <span class="kwrd">Me</span>.txtPageBody.Text.Length &lt; 1 
    <span class="kwrd">Then</span>
        MessageBox.Show(<span class="str">&quot;Please enter a title and description.&quot;</span>)
        <span class="kwrd">Return</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">Dim</span> args <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument()
    <span class="kwrd">Dim</span> page <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;page&quot;</span>)
    <span class="kwrd">Dim</span> title <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;title&quot;</span>)
    title.InnerText = <span class="kwrd">Me</span>.txtPageTitle.Text.Trim()
    <span class="kwrd">Dim</span> description <span class="kwrd">As</span> XmlElement = args.CreateElement(<span class="str">&quot;description&quot;</span>)
    description.InnerText = <span class="kwrd">Me</span>.txtPageBody.Text.Trim()

    page.AppendChild(title)
    page.AppendChild(description)

    <span class="kwrd">Me</span>._request.ExecuteWebMethod(<span class="kwrd">Me</span>._webMethodPath, page)
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>API operations that don't require any XML other than the service token are all handled by a catch-all method that just fires off the URL against a helper method:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> InvokeSimpleMethod()
{
    <span class="kwrd">this</span>._request.ExecuteWebMethod(<span class="kwrd">this</span>._webMethodPath);
}
</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> InvokeSimpleMethod()
    <span class="kwrd">Me</span>._request.ExecuteWebMethod(<span class="kwrd">Me</span>._webMethodPath)
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Also note: I don't pass the URL and other goodies into these delegated methods, as I need them to be void methods (<b>Sub</b>s in VB.NET parlance) that contain no arguments so that their signature matches that of the
<b>System.Threading.ThreadStart</b> delegate. </p>
<h5>Connection Goodness, Revisited</h5>
<p>To avoid scattering connection logic and the API key all throughout the application, I then created a class called a
<b>BackPackRequest</b> class to abstract out all of the connection details. Its purpose is to abstract connection details away from the callers and provide a uniform way to ensure that calls to the BackPack service are properly formatted, and all provided with
 the requisite service token. </p>
<p>Each time user credentials (username and API Key) are entered, or changed in the Winform, a new instance of the
<b>BackPackRequest</b> object is created, which requires the account name, API Key, and a logging delegate (more on that in a second) in the constructor. The constructor wires up the base BackPack URL, squirrels away the API key for each subsequent connection
 request, and offers a handful of overloads to one single point of contact to callers—a method that takes, effectively, a method location URL along with an optional array of
<b>XmlElements</b> serving as arguments where needed. </p>
<p>In order to include the service token in each request, a private helper method was created to join the always-required token, wrapped in a request element, with any optional
<b>XmlElements</b> representing user input. However, building that chunk of XML required floating elements off of a new, blank
<b>XmlDocument</b> owned by the <b>BackPackRequest</b> instance. The optional elements to append would actually be coming from another document—causing a bit of a problem: while you can float new elements on a document and append them as desired, you can't
 &quot;float&quot; them on to another document. It wouldn't make any sense to have two classes (the Winform and the
<b>BackPackRequest</b> instance) share a single <b>XmlDocument</b> in order to create nodes from a common trunk (that would be an unbearable coupling faux pas)—so I had to import the nodes from one document to the other. Again, the Framework makes this quite
 easy, and as you can see below, the logic to add zero to multiple elements was pretty easy to implement with the use of the
<b>XmlDocument</b>'s <b>ImportNode()</b> method: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> XmlNode BuildCommand(XmlElement[] args)
{
    XmlDocument command = <span class="kwrd">new</span> XmlDocument();
    XmlElement request = command.CreateElement(<span class="str">&quot;request&quot;</span>);
    XmlElement token = command.CreateElement(<span class="str">&quot;token&quot;</span>);

    token.InnerText = <span class="kwrd">this</span>._apiKey;
    request.AppendChild(token);
    command.AppendChild(request);

    <span class="kwrd">if</span> (args != <span class="kwrd">null</span>)
    {
        <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; args.Length; i&#43;&#43;)
        {
            XmlNode arg = command.ImportNode(args[i], <span class="kwrd">true</span>);
            request.AppendChild(arg);
        }
    }

    <span class="kwrd">return</span> command.SelectSingleNode(<span class="str">&quot;/&quot;</span>); <span class="rem">// root</span>
}
</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Function</span> BuildCommand(<span class="kwrd">ByVal</span> args() <span class="kwrd">As</span> XmlElement) <span class="kwrd">As</span> XmlNode

    <span class="kwrd">Dim</span> command <span class="kwrd">As</span> XmlDocument = <span class="kwrd">New</span> XmlDocument()
    <span class="kwrd">Dim</span> request <span class="kwrd">As</span> XmlElement = command.CreateElement(<span class="str">&quot;request&quot;</span>)
    <span class="kwrd">Dim</span> token <span class="kwrd">As</span> XmlElement = command.CreateElement(<span class="str">&quot;token&quot;</span>)

    token.InnerText = <span class="kwrd">Me</span>._apiKey
    request.AppendChild(token)
    command.AppendChild(request)

    <span class="kwrd">If</span> <span class="kwrd">Not</span> args <span class="kwrd">Is</span> <span class="kwrd">Nothing</span> <span class="kwrd">Then</span>
        <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span>
        <span class="kwrd">For</span> i = 0 <span class="kwrd">To</span> args.Length - 1 <span class="kwrd">Step</span> i &#43; 1
            <span class="kwrd">Dim</span> arg <span class="kwrd">As</span> XmlNode = command.ImportNode(args(i), <span class="kwrd">True</span>)
            request.AppendChild(arg)
        <span class="kwrd">Next</span>
    <span class="kwrd">End</span> <span class="kwrd">If</span>

    <span class="kwrd">Return</span> command.SelectSingleNode(<span class="str">&quot;/&quot;</span>) <span class="rem">' root</span>
<span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Note that in the above code, I'm making a deep copy of the nodes that are being imported (the second argument of
<b>ImportNode()</b> is set to true). A shallow copy would only have served to import the element in name only—without the inner data.
</p>
<h5>Logging XML Interaction Details</h5>
<p>The only big thing left at this point was to wire up logging functionality in the Winform. Each invocation of the delegate by the
<b>BackPackRequest</b> instance sends information back to the Winform without the request really even knowing or caring what it is doing—which is why Delegates are such powerful tools, and such great allies in the war on coupling.
</p>
<p>To handle the logging needs, and to account for the connectivity functionality mentioned above, the initial connection logic introduced early ended up being augmented into a full-blown method, which gets executed asynchronously as follows:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">internal</span> <span class="kwrd">string</span> ExecuteWebMethod(<span class="kwrd">string</span> methodLocation, XmlElement[] args)
{
    <span class="kwrd">try</span>
    {
        <span class="kwrd">string</span> url = <span class="kwrd">this</span>._url &#43; methodLocation;
        XmlNode xmlCommandNode = <span class="kwrd">this</span>.BuildCommand(args);

        <span class="kwrd">string</span> xml = xmlCommandNode.InnerXml;
        <span class="kwrd">this</span>._screenWriter(<span class="str">&quot; &quot;</span>);
        <span class="kwrd">this</span>._screenWriter(<span class="str">&quot;Send: (&quot;</span> &#43; url &#43; <span class="str">&quot;)&quot;</span> &#43; System.Environment.NewLine &#43; xml);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

        request.Method = <span class="str">&quot;POST&quot;</span>;
        <span class="rem">// ... </span>
        <span class="rem">// elided - (this is the exact same connection code as listed initially)</span>
        <span class="rem">// ...    </span>
        responseBody.Close();

        <span class="kwrd">this</span>._screenWriter(<span class="str">&quot;Response:&quot;</span> &#43; System.Environment.NewLine &#43; responseInfo);
        <span class="kwrd">return</span> responseInfo;
    }
    <span class="kwrd">catch</span> (Exception ex)
    {
        <span class="kwrd">this</span>._screenWriter(<span class="str">&quot;EXCEPTION: &quot;</span> &#43; ex.ToString());
        <span class="kwrd">return</span> <span class="kwrd">null</span>;
    }
}
</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Friend</span> <span class="kwrd">Function</span> ExecuteWebMethod(<span class="kwrd">ByVal</span> methodLocation <span class="kwrd">As</span> <span class="kwrd">String</span>, 
    <span class="kwrd">ByVal</span> args() <span class="kwrd">As</span> XmlElement) <span class="kwrd">As</span> <span class="kwrd">String</span>
    <span class="kwrd">Try</span>
        <span class="kwrd">Dim</span> url <span class="kwrd">As</span> <span class="kwrd">String</span> = <span class="kwrd">Me</span>._url &#43; methodLocation
        <span class="kwrd">Dim</span> xmlCommandNode <span class="kwrd">As</span> XmlNode = <span class="kwrd">Me</span>.BuildCommand(args)

        <span class="rem">' if (isOnline)</span>
        <span class="rem">' otherwise, append the two args into a single element, and </span>
        <span class="rem">' append it to another thingy.</span>

        <span class="kwrd">Dim</span> xml <span class="kwrd">As</span> <span class="kwrd">String</span> = xmlCommandNode.InnerXml
        <span class="kwrd">Me</span>._screenWriter(<span class="str">&quot; &quot;</span>)
        <span class="kwrd">Me</span>._screenWriter(<span class="str">&quot;Send: (&quot;</span> &#43; url &#43; <span class="str">&quot;)&quot;</span> &#43; 
            System.Environment.NewLine &#43; xml)
        <span class="kwrd">Dim</span> request <span class="kwrd">As</span> HttpWebRequest = <span class="kwrd">CType</span>(WebRequest.Create(url), 
            HttpWebRequest)

        request.Method = <span class="str">&quot;POST&quot;</span>
        request.Headers.Add(<span class="str">&quot;X-POST_DATA_FORMAT&quot;</span>, <span class="str">&quot;xml&quot;</span>)
        request.ContentType = <span class="str">&quot;application/xml&quot;</span>

        <span class="rem">' won't work: needs to be encoded:</span>
        request.ContentLength = xml.Length
        <span class="kwrd">Dim</span> post <span class="kwrd">As</span> StreamWriter = 
            <span class="kwrd">New</span> StreamWriter(request.GetRequestStream())
        post.Write(xml)
        post.Close()

        <span class="kwrd">Dim</span> response <span class="kwrd">As</span> HttpWebResponse = <span class="kwrd">CType</span>(request.GetResponse(), 
            HttpWebResponse)

        <span class="kwrd">Dim</span> responseBody <span class="kwrd">As</span> StreamReader = 
            <span class="kwrd">New</span> StreamReader(response.GetResponseStream())
        <span class="kwrd">Dim</span> responseInfo <span class="kwrd">As</span> <span class="kwrd">String</span> = responseBody.ReadToEnd()
        responseBody.Close()

        <span class="kwrd">Me</span>._screenWriter(<span class="str">&quot;Response:&quot;</span> &#43; System.Environment.NewLine &#43; 
            responseInfo)
        <span class="kwrd">Return</span> responseInfo
        <span class="kwrd">Catch</span> ex <span class="kwrd">As</span> Exception
            <span class="kwrd">Me</span>._screenWriter(<span class="str">&quot;EXCEPTION: &quot;</span> &#43; ex.ToString())
            <span class="kwrd">Return</span> <span class="kwrd">Nothing</span>
    <span class="kwrd">End</span> <span class="kwrd">Try</span>
<span class="kwrd">End</span> Function</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>Only, there's an issue with that code: a background thread will be executing the code above, and the point of logging is to write the info written to the
<b>txtLog</b> TextBox on our Winform. Winforms, however, get exceptionally cranky (literally) about a background thread touching their user controls (only the UI thread or owner of the controls can touch them). To account for this, we need to direct the delegate
 at a simple method that will store the log information in a local variable and then inform the UI thread that there's some new information to log to the screen:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> OnLogged(<span class="kwrd">string</span> info)
{
    <span class="kwrd">this</span>._logMessage = info;
    <span class="kwrd">this</span>.BeginInvoke(<span class="kwrd">new</span> MethodInvoker(<span class="kwrd">this</span>.BindLogMessage));
}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> OnLogged(<span class="kwrd">ByVal</span> info <span class="kwrd">As</span> <span class="kwrd">String</span>)
    <span class="kwrd">Me</span>._logMessage = info
    <span class="kwrd">Me</span>.BeginInvoke(<span class="kwrd">New</span> MethodInvoker(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.BindLogMessage))
<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>And when it comes time to paint the logged information to the screen, we need a way of &quot;scrolling&quot; the contents in the textbox so that the latest results are output as they are received. I accomplished this by capturing the control that currently has focus,
 stealing the focus and directing it to the <b>txtLog</b> TextBox, outputting the text, scrolling the text box to the end of its contents, and then returning control back to the control that should truly have it:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">private</span> <span class="kwrd">void</span> BindLogMessage()
{
    <span class="rem">// probably should pay attention to race conditions/locking/etc.</span>
    <span class="kwrd">this</span>.txtLog.Text &#43;= System.Environment.NewLine &#43; <span class="kwrd">this</span>._logMessage;

    <span class="rem">// handle jiggling, focus stealing, output scrolling, voodo:</span>
    Control current = <span class="kwrd">this</span>.ActiveControl;
    <span class="kwrd">this</span>.txtLog.Focus();

    <span class="kwrd">this</span>.txtLog.SelectionStart = <span class="kwrd">this</span>.txtLog.Text.Length;
    <span class="kwrd">this</span>.txtLog.SelectionLength = 0;
    <span class="kwrd">this</span>.txtLog.ScrollToCaret();

    current.Focus();
    Application.DoEvents();
    
}</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p><b>Visual Basic</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Private</span> <span class="kwrd">Sub</span> BindLogMessage()
    <span class="rem">' probably should pay attention to race conditions/locking/etc.</span>
    <span class="kwrd">Me</span>.txtLog.Text &#43;= System.Environment.NewLine &#43; <span class="kwrd">Me</span>._logMessage

    <span class="rem">' handle jiggling, focus stealing, output scrolling, voodo:</span>
    <span class="kwrd">Dim</span> current <span class="kwrd">As</span> Control = <span class="kwrd">Me</span>.ActiveControl
    <span class="kwrd">Me</span>.txtLog.Focus()

    <span class="kwrd">Me</span>.txtLog.SelectionStart = <span class="kwrd">Me</span>.txtLog.Text.Length
    <span class="kwrd">Me</span>.txtLog.SelectionLength = 0
    <span class="kwrd">Me</span>.txtLog.ScrollToCaret()

    current.Focus()
    Application.DoEvents()

<span class="kwrd">End</span> Sub</pre>
<style type="text/css">
<!--
.csharpcode
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{font-size:small;
	color:black;
	font-family:consolas,"Courier New",courier,monospace;
	background-color:#ffffff}
.csharpcode 
	{margin:0em}
.csharpcode .rem
	{color:#008000}
.csharpcode .kwrd
	{color:#0000ff}
.csharpcode .str
	{color:#006080}
.csharpcode .op
	{color:#0000c0}
.csharpcode .preproc
	{color:#cc6633}
.csharpcode .asp
	{background-color:#ffff00}
.csharpcode .html
	{color:#800000}
.csharpcode .attr
	{color:#ff0000}
.csharpcode .alt
	{margin:0em;
	width:100%;
	background-color:#f4f4f4}
.csharpcode .lnum
	{color:#606060}
-->
</style>
<p>It feels a bit like a hack, but I couldn't think of a better way to do it given the fact that that scrolling requires that the control to be &quot;scrolled&quot; have focus.
</p>
<h5>Test Driving your BackPack </h5>
<p>At this point, we've got a user interface that routes operation choices into a single event handler that determines the correct URL to invoke, assembles any required user input into XML, and then fires it off against the server. It has been a bit of a long
 road, but Page functionality from the BackPack API is now fully implemented and can be taken for a test drive:
</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_3.gif"><img alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/913316/BackPackAPI_PartI_3_thumb.gif" border="0"></a>
</p>
<p><b>(click image to zoom)</b> </p>
<p>Once you enter your Account Name and API Key details (and leave the Connection Information Group Box), the Winform detects that both fields have been filled out and creates an instance of the
<b>BackPackRequest</b> class in the background, so you can then press the Load Pages button to load your pages (if you have any—if not, you can create a page, and then Load Pages). Once your pages are loaded, you can destroy pages, rename them, or link and
 share them, etc. You can even direct BackPack to email you a copy of your pages—which, for some reason, is very satisfying to my inner geek.
</p>
<h4>Conclusion—Part I </h4>
<p>So, we've taken a look at an XML API, and played around with dynamically generating XML documents using the DOM to build &quot;data grams&quot; from our own crude user interface. We've largely ignored using or consuming the returned XML, with the exception of the
 Pages List box, which simply iterates through the returned pages nodes and binds them to a Hashtable and to the List Box. Otherwise, the only use we make of the XML returned from the service is to output it to the Winform via the logging functionality.
</p>
<p>However, in the next article we'll take a better look at how to usefully and effectively consume the returned XML. In addition to fleshing out the rest of the API, we'll also make our application functional—by making it so that we can grab BackPack data
 from the web, go offline, make updates and changes in our application, and then marshal those changes back up to the server when we get back online. It should make for a very cool tool once we're done.
</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michael-K-Campbell/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:fc5874617e79484c9d469e7600dabacd">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-I</comments>
      <itunes:summary>



&amp;nbsp;
This article discusses how to set up a free BackPack account, grab the XML Token needed to interact with the BackPack web service, and delve into connecting to the server to send commands and data back and forth.



Michael K. Campbell


Difficulty: Intermediate
Time Required: 
1-3 hours
Cost: Free
Software: Visual Studio Express Editions,
BackPack API
Hardware: 
Download:


C# Download

VB Download










&amp;nbsp; 
In the &amp;quot;old days&amp;quot; there was a debate that raged between Palm and Windows CE zealots. The focus of the debate was a question of whether Palm, with its simple OS and simple functionality, was better suited to meeting users needs, or whether Windows CE, with
 all of its complex functionality, provided a better option. In simplest terms, the argument was really a question of which was more. Was more more, or was less more? I was always of the impression that more was more—at least in that debate.
 
But sometimes less can definitely be more. Enter a small company made up of five individuals that understands this very well:
37 Signals. They&#39;ve successfully launched three VERY SIMPLE online applications that have made them nearly legendary in the web development community. The secret of their success: carefully targeted applications that
 leverage cutting-edge technology to make collaboration intuitive through absurdly clean and simple user interfaces that anyone can quickly and easily use. Couple those strengths with a &amp;quot;first hit is free&amp;quot; marketing model to compel users to upgrade to paid
 services for improved productivity, and it&#39;s not hard to see why they&#39;ve done so well.
 
Glad you like the 37 Signals Kool-Aid, but I thought this was an article about XML?
One of the great things about XML is that it is close to becoming ubiquitous. It really is becoming the lingua franca of data transfer. (There&#39;s still an inordinate amount of delimited, flat-file, legacy, evil out there in the corporate universe, though.)
 37 Signals obviou</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-I</link>
      <pubDate>Tue, 31 Oct 2006 15:38:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-I</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913316_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/913316_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michael K. Campbell</dc:creator>
      <itunes:author>Michael K. Campbell</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-I/RSS</wfw:commentRss>
    </item>    
</channel>
</rss>