<?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-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-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-Campbell/Posts</link>
    <language>en</language>
    <pubDate>Sat, 18 May 2013 18:42:34 GMT</pubDate>
    <lastBuildDate>Sat, 18 May 2013 18:42:34 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>1</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Harnessing the BackPack API - Part IV</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. This IV adds the ability to remove, or delete pages, notes, tasks, etc.</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/912387/BackPackAPI_PartIV_CS.msi">C# Download</a>
</li><li><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/912387/BackPackAPI_PartIV_VB.msi">VB Download</a></li></ul>
</div>
</td>
</tr>
</tbody>
</table>
</span>
<h4>Previously on BackPack API...</h4>
<p>Well, here we are: on the fourth and final installment of the articles on Xml4Fun dedicated to exploring the BackPack API. In the previous articles we've covered a lot of ground. We covered the API itself in the first article, along with ways to translate
 user input into dynamically generated XML and pass data back and forth between our application and the BackPack servers. In the second article we took things a step further by creating an object model, using it to consume data expressed as XML, and configuring
 it so that it could consume that XML either from disk or from the web—all without any noticeable difference to our application. In the third article we examined the flow of information between our user interface, the middle tier, the BackPack servers, and
 then back out to the UI again (via the middle tier). We also added a <b>TreeView</b> control to visually represent our BackPack data, and loaded each
<b>TreeNode</b>'s <b>Tag</b> property with a <b>ResourceDescriptor</b> object designed to allow for quick and easy lookups to the kind of data represented.
</p>
<h4>Remove/Delete</h4>
<p>In previous articles, we've worked on the basics of our object Model, but left out a key component: the ability to remove, or delete pages, notes, tasks, etc. Coding the functionality to remove objects is fairly straightforward, and just involves wiring
 up a bit of logic to our already existing infrastructure. Adding a new Context Menu item allows users to right-click and delete nodes.
</p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/912387/backpackapi_part4_1.gif" border="0">
</p>
<p>When end users select the delete option, the node's <b>Tag</b> property is evaluated to determine what kind of node (Page, Task, Note, etc.) is being flagged for deletion. A command representing the deletion request is then assembled by either the
<b>PageManager</b> or <b>Page</b> in question (if it's the child object of a Page that is being deleted), and the command is then routed to the local
<b>BackPackGateway</b> instance for processing against the BackPack servers. Once the operation is completed on against the servers, the
<b>PageManger</b> removes the corresponding <b>PendingOperation</b> instance representing the operation in question, modifies any local data as needed (i.e., deletes it) and then notifies the UI that the operation has completed, upon which the UI can remove
 the corresponding node in question from the <b>TreeView</b>. </p>
<p>There is, however, one catch: when <b>Pages</b> assemble commands for processing on the server, they don't communicate those commands directly to the
<b>BackPackGateway</b> object. Instead, they raise an event that lets the <b>PageManager</b> know that one of its
<b>Page</b>s needs to marshal a change up to the server. The <b>PageManager</b>, in turn, determines whether to push the change immediately (if online) or store it for processing later (once connectivity has been restored). The problem is that because
<b>Page</b>s announce their changes via events, we need to unbind event handlers in the
<b>PageManger</b> before we can remove any given <b>Page</b>. Removing an event handler is a fairly straightforward operation, and looks like the following:
</p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><pre class="csharpcode"><pre class="csharpcode">Page removed = e.PendingOperation.State <span class="kwrd">as</span> Page;<br><span class="kwrd">if</span> (removed != <span class="kwrd">null</span>)<br>{<br>    removed.OperationAssembled -= <br>         <span class="kwrd">new</span> OperationAssembledEventHandler(<span class="kwrd">this</span>.Page_OperationAssembled);<br>    <span class="kwrd">this</span>._pages.Remove(removed);<br>    removed = <span class="kwrd">null</span>;<br>}
</pre></pre></pre>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Dim</span> removed <span class="kwrd">As</span> Page = <span class="kwrd">CType</span>(e.PendingOperation.State, Page)<span class="kwrd"><br><br>
<pre class="csharpcode"><span class="kwrd">If</span> (<span class="kwrd">Not</span> (removed) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) <span class="kwrd">Then</span><br>     <span class="kwrd">RemoveHandler</span> removed.OperationAssembled, <br>           <span class="kwrd">New</span> OperationAssembledEventHandler(<br>           <span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>.Page_OperationAssembled)<br>     <span class="kwrd">Me</span>._pages.Remove(removed)<br>     removed = <span class="kwrd">Nothing</span><br><span class="kwrd">End</span> If</pre></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>Once the event handler is removed, the page can then be dropped from the middle tier, and the
<b>PageManager</b> can inform the UI that the page is now gone, upon which the corresponding
<b>Node</b> (and all associated lookups) can then be removed from the UI tier. If you traverse the code that's required to delete BackPack data from beginning to end, you'll see that there's an awful lot of activity involved. Part of it is housekeeping functionality
 spread over two tiers (UI and a business tier), part of it is threading code designed to ensure that the application's Winform stays responsive while everything occurs in the background, and a large portion of the code involved relates to handling the commands
 themselves and what to do with the commands based upon network connectivity. </p>
<h4>Network Awareness (It's alive!!!) </h4>
<p>The ability to determine current network connectivity and detect changes is a pretty critical piece of functionality for an application whose stated goal is to allow you to work with an online application while you are offline. As such, we need a clean way
 to determine network connectivity. Happily the 2.0 version of .NET Framework introduces a bunch of new functionality that makes all of that possible. The new
<b>System.Net.NetworkInformation</b> namespace presents a number of very handy classes and utilities that let you easily determine your current network status, as well as alert you to changes in that status provided that you set up the proper event handlers.
 The functionality is, however, spread across a number of classes, so encapsulating core sections of that logic into a single class will make interacting with that functionality much easier for our application. The abstraction is really nothing special, and
 in the interest of time I'm going to skip detailing the implementation (the included code
<b>NetworkStatus.cs/vb</b> should be clear enough—though I did <a href="http://blog.angrypets.com/2005/10/its_all_about_a.html">
blog</a> about the implementation a while back if you'd like more info). Once successfully abstracted, the
<b>NetworkStatus</b> class ends up looking like so: </p>
<p><img alt="" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/912387/backpackapi_part4_2.gif" border="0">
</p>
<p>Adding an instance of the <b>NetworkStatus</b> class to the <b>PageManager</b> enables it to determine current network connectivity status and handle requested changes as needed by either routing them directly to the Server (via the
<b>BackPackGateway</b> object), or by adding them to the <b>PageManager</b>'s internal collection of
<b>Pending Commands</b> that will be run as soon as connectivity is re-established. If the application is closed prior to regaining connectivity, the pending commands will be persisted to disk to ensure that they are not lost—enabling us to take our BackPack
 data offline, and even make modifications while offline. </p>
<p><b>Visual C#</b><br>
</p>
<pre class="csharpcode"><span class="kwrd">
<pre class="csharpcode"><span class="kwrd"><span class="kwrd">bool</span> connected = <br>     <span class="kwrd">this</span>._networkStatus.ConnectivityStatus == ConnectionStatus.Connected;<br><span class="kwrd">bool</span> gatewayConfigured = (<span class="kwrd">this</span>._gateway != <span class="kwrd">null</span> &amp;&amp;<br>     <span class="kwrd">this</span>._gateway.ConnectionInfo != <span class="kwrd">null</span>);<br><span class="kwrd">if</span>(connected &amp;&amp; gatewayConfigured) <br>{<br>    AsyncRemoteOperation async =<br>          <span class="kwrd">new</span> AsyncRemoteOperation(<span class="kwrd">this</span>._gateway.ExecuteWebMethod);<br>    async.BeginInvoke(url, args, operation, <span class="kwrd">null</span>, <span class="kwrd">null</span>);<br>}<br><span class="kwrd">else</span><br>{<br>    <span class="kwrd">this</span>._pendingCommands.Add(<span class="kwrd">new</span> Command(url,args,operation));<br>}<br></span></pre></span><span class="kwrd"></span></pre>
<p><b>Visual Basic</b> </p>
<code></code><span class="kwrd"></span>
<pre class="csharpcode"><span class="kwrd">Dim</span> connected <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = <br>     (<span class="kwrd">Me</span>._networkStatus.ConnectivityStatus = ConnectionStatus.Connected)<br><span class="kwrd">Dim</span> gatewayConfigured <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = ((<span class="kwrd">Not</span> (<span class="kwrd">Me</span>._gateway) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) _<br>           <span class="kwrd">AndAlso</span> (<span class="kwrd">Not</span> (<span class="kwrd">Me</span>._gateway.ConnectionInfo) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>))<br><span class="kwrd">If</span> (connected <span class="kwrd">AndAlso</span> gatewayConfigured) <span class="kwrd">Then</span><br>    <span class="kwrd">Dim</span> async <span class="kwrd">As</span> AsyncRemoteOperation = <br>          <span class="kwrd">New</span> AsyncRemoteOperation(<span class="kwrd">AddressOf</span> <span class="kwrd">Me</span>._gateway.ExecuteWebMethod)<br>    async.BeginInvoke(url, args, operation, <span class="kwrd">Nothing</span>, <span class="kwrd">Nothing</span>)<br><span class="kwrd">Else</span><br>    <span class="kwrd">Me</span>._pendingCommands.Add(<span class="kwrd">New</span> Command(url, args, operation))<br><span class="kwrd">End</span> If</pre>
<pre class="csharpcode"><b></b><span class="kwrd"></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>And, of course, because of the way everything has been architected, the UI is, effectively, oblivious to all of this and can provide almost full functionality while offline. I made the decision to disallow edits to newly created objects while offline merely
 to keep synchronization of temporary IDs to a minimum while offline. </p>
<h4>Persisting Commands</h4>
<p>One of the great things about developing applications with an object model is that as you get closer to the finish line, tasks tend to become increasingly easier to complete, as they are able to leverage existing code and functionality. Because of all of
 the work already done to persist various collections of objects, persisting commands is a terribly easy task. When the user closes the Winform, logic will check to see if any pending operations were added during the current session. If they were, the user
 will be prompted to save their changes as so: </p>
<p><b>Visual C#</b> </p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">bool</span> changesPending = <span class="kwrd">this</span>._pageManager.PendingOperations.Count &gt; 0;<br><br><span class="rem">// changes may BE pending - but they could be from a previous session, </span><br><span class="rem">//     in which case there is no need to save</span><br><span class="kwrd">bool</span> madeThisSession = <span class="kwrd">this</span>._pageManager.ChangeCount &gt; 0;<br><br><span class="kwrd">if</span> (changesPending &amp; madeThisSession)<br>{<br>    <span class="kwrd">string</span> message = <span class="str">&quot;Changes made are still pending against the &quot;</span> &#43;<br>        <span class="str">&quot;server. Do you wish to save changes from this Session?&quot;</span> &#43;<br>        System.Environment.NewLine &#43; <span class="str">&quot;(Changes made in previous &quot;</span> &#43;<br>        <span class="str">&quot;Sessions will still be persisted if you don't save now.)&quot;</span>;<br><br>    DialogResult res = MessageBox.Show(<br>        message, <span class="str">&quot;Save Changes?&quot;</span>, MessageBoxButtons.YesNoCancel);<br>    <span class="kwrd">switch</span> (res)<br>    {<br>        <span class="kwrd">case</span> DialogResult.Cancel:<br>            e.Cancel = <span class="kwrd">true</span>;<br>            <span class="kwrd">return</span>;<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> DialogResult.No:<br>            <span class="kwrd">this</span>._pageManager.DeletePendingChanges();<br>            <span class="kwrd">this</span>._pageManager.DeleteStateFiles(<span class="kwrd">true</span>);<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">case</span> DialogResult.Yes:<br>            <span class="kwrd">this</span>._pageManager.PersistPages();<br>            <span class="kwrd">this</span>._pageManager.PersistCommands();<br>            <span class="kwrd">break</span>;<br>        <span class="kwrd">default</span>:<br>            e.Cancel = <span class="kwrd">true</span>;<br>            <span class="kwrd">return</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> </p>
<code></code><span class="kwrd"></span>
<pre class="csharpcode"><span class="kwrd">
<pre class="csharpcode"><span class="kwrd">Dim</span> changesPending <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = (<span class="kwrd">Me</span>._pageManager.PendingOperations.Count &gt; 0)<br><br><span class="rem">' changes may BE pending - but they could be </span><br><span class="rem">' from a previous session, in which case there is no need to save</span><br><span class="kwrd">Dim</span> madeThisSession <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = (<span class="kwrd">Me</span>._pageManager.ChangeCount &gt; 0)<br><br><span class="kwrd">If</span> (changesPending <span class="kwrd">And</span> madeThisSession) <span class="kwrd">Then</span><br>    <span class="kwrd">Dim</span> message <span class="kwrd">As</span> <span class="kwrd">String</span> = (<span class="str">&quot;Changes made are still pending against the&quot;</span>&#43;<br>        <span class="str">&quot;server. Do you wish to save changes from this Session?&quot;</span> _<br>         &#43; (System.Environment.NewLine &#43; <span class="str">&quot;(Changes made in previous&quot;</span>&#43;<br>         <span class="str">&quot; Sessions will still be persisted if you don't save now.)&quot;</span>))<br><br>    <span class="kwrd">Dim</span> res <span class="kwrd">As</span> DialogResult = MessageBox.Show(message, <span class="str">&quot;Save Changes?&quot;</span>, <br>        MessageBoxButtons.YesNoCancel)<br>    <span class="kwrd">Select</span> <span class="kwrd">Case</span> (res)<br>        <span class="kwrd">Case</span> DialogResult.Cancel<br>            e.Cancel = <span class="kwrd">True</span><br>            <span class="kwrd">Return</span><br>        <span class="kwrd">Case</span> DialogResult.No<br>            <span class="kwrd">Me</span>._pageManager.DeletePendingChanges()<br>            <span class="kwrd">Me</span>._pageManager.DeleteStateFiles(<span class="kwrd">True</span>)<br>        <span class="kwrd">Case</span> DialogResult.Yes<br>            <span class="kwrd">Me</span>._pageManager.PersistPages()<br>            <span class="kwrd">Me</span>._pageManager.PersistCommands()<br>        <span class="kwrd">Case</span> <span class="kwrd">Else</span><br>            e.Cancel = <span class="kwrd">True</span><br>            <span class="kwrd">Return</span><br>    <span class="kwrd">End</span> <span class="kwrd">Select</span><br><span class="kwrd">End</span> If</pre></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>The calls to <b>PersistPages()</b> and <b>PersistCommands()</b> just wrap calls to the helper method
<b>SerializeToFile()</b> created in <a href="http://msdn.microsoft.com/coding4fun/xmlforfun/BackPackAPI_Part2/default.aspx">
Article #2</a>. That method serializes a collection of generics to disk. </p>
<p>Each time the Winform is loaded, the <b>PageManger</b> will look for persisted
<b>Commands</b> as well as <b>Pending Operations</b> and flag their existence as needed. If the end-user then logs in and loads
<b>Page</b>s from the server, all pending operations are discarded (the assumption is that they're getting a new copy of the data from the server, instead of loading their previous, offline changes). If the end-user loads the
<b>Page</b>s from disk, any pending operations against that data are then loaded as well.
<b>Pending Commands</b>, if there are any, will be immediately executed against the server provided user credentials are provided. (Likewise, pending commands &quot;rolling around in memory&quot; will also be executed against the Server if network connectivity is restored
 while the application is in operation and has been running in offline mode.) </p>
<p>Of course, managing the interaction and various permutations between all of the menu options, connectivity states, and permutations of pending operations was a bit messy. I believe my implementation of the various business rules governing what to do based
 upon &quot;pending-ness,&quot; and connectivity is fairly logical—but it's entirely possible that the way I implemented these choices may not mesh with everyone's logic. (I regret nothing!) That's the bad news. The good news, however, is that while determining when
 to send pending commands to the server is a bit tricky, actually doing it is a snap. Commands themselves are nothing more than persisted data sent into a single method, so putting commands back into play involves nothing more than just sending them back to
 the method in question. For example, I've tapped the event handler that detects when network connectivity returns to &quot;rehydrate&quot; commands, and in that routine I just thaw out any commands that were serialized to disk, and add them to the list of existing pending
 commands already in memory, and then send the whole lot off to be processed as follows:
</p>
<p><b>Visual C#</b><br>
</p>
<pre class="csharpcode"><span class="kwrd"><br>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">void</span> NetworkStatusChanged(<span class="kwrd">object</span> sender,<br>      NetworkStatusChangedEventArgs e)<br>{<br>    <span class="kwrd">bool</span> online = e.ConnectionState == ConnectionStatus.Connected;<br>    <span class="kwrd">bool</span> connected = <span class="kwrd">this</span>._gateway != <span class="kwrd">null</span> &amp;&amp; <span class="kwrd">this</span>._gateway.Loaded;<br>    <span class="kwrd">if</span>(online &amp;&amp; connected) <br>    {<br>        <span class="kwrd">if</span>(<span class="kwrd">this</span>._savedCommands)<br>        {<br>            SerializableList&lt;Command&gt; savedCommands = (SerializableList&lt;Command&gt;)<br>                 <span class="kwrd">this</span>.LoadSerializableList(System.Environment.CurrentDirectory &#43; <br>                 CommandsFileName, <span class="kwrd">typeof</span>(SerializableList&lt;Command&gt;));<br><br>            <span class="kwrd">if</span> (savedCommands != <span class="kwrd">null</span> &amp;&amp; savedCommands.Count &gt; 0)<br>            {<br>                <span class="kwrd">foreach</span> (Command c <span class="kwrd">in</span> savedCommands)<br>                {<br>                    <span class="kwrd">if</span> (!<span class="kwrd">this</span>._pendingCommands.Contains(c))<br>                        <span class="kwrd">this</span>._pendingCommands.Add(c);<br>                }<br>            }<br>        }<br><br>        <span class="kwrd">if</span> (<span class="kwrd">this</span>._pendingCommands.Count &gt; 0)<br>        {<br>            Command[] queued = <span class="kwrd">new</span> Command[<span class="kwrd">this</span>._pendingCommands.Count];<br>            <span class="kwrd">this</span>._pendingCommands.CopyTo(queued); <br>            <span class="kwrd">this</span>.ProcessPendingCommands(queued);<br>        }<br>    }<br>}<br></pre></span></pre>
<p><b>Visual Basic</b></p>
<pre><code></code></pre>
<pre class="csharpcode"><span class="kwrd">Public</span> <span class="kwrd">Sub</span> NetworkStatusChanged(<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> NetworkStatusChangedEventArgs)<br>    <span class="kwrd">Dim</span> online <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = (e.ConnectionState = ConnectionStatus.Connected)<br>    <span class="kwrd">Dim</span> connected <span class="kwrd">As</span> <span class="kwrd">Boolean</span> = ((<span class="kwrd">Not</span> (<span class="kwrd">Me</span>._gateway) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) _<br>                    <span class="kwrd">AndAlso</span> <span class="kwrd">Me</span>._gateway.Loaded)<br>    <span class="kwrd">If</span> (online <span class="kwrd">AndAlso</span> connected) <span class="kwrd">Then</span><br>        <span class="kwrd">If</span> <span class="kwrd">Me</span>._savedCommands <span class="kwrd">Then</span><br>            <span class="kwrd">Dim</span> savedCommands <span class="kwrd">As</span> SerializableList(Of Command) = <br>            <span class="kwrd">CType</span>(<span class="kwrd">Me</span>.LoadSerializableList((<br>                System.Environment.CurrentDirectory &#43; CommandsFileName),<br>                <span class="kwrd">GetType</span>(SerializableList(Of Command))), SerializableList(<br>                Of Command))<br><br>            <span class="kwrd">If</span> ((<span class="kwrd">Not</span> (savedCommands) <span class="kwrd">Is</span> <span class="kwrd">Nothing</span>) _<br>                        <span class="kwrd">AndAlso</span> (savedCommands.Count &gt; 0)) <span class="kwrd">Then</span><br>                <span class="rem">'this._pendingCommands.AddRange(savedCommands); (would </span><br>                <span class="rem">'work, but would also create dupes/collisions)</span><br>                <span class="kwrd">For</span> <span class="kwrd">Each</span> c <span class="kwrd">As</span> Command <span class="kwrd">In</span> savedCommands<br>                    <span class="kwrd">If</span> <span class="kwrd">Not</span> <span class="kwrd">Me</span>._pendingCommands.Contains(c) <span class="kwrd">Then</span><br>                        <span class="kwrd">Me</span>._pendingCommands.Add(c)<br>                    <span class="kwrd">End</span> <span class="kwrd">If</span><br>                <span class="kwrd">Next</span><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">If</span> (<span class="kwrd">Me</span>._pendingCommands.Count &gt; 0) <span class="kwrd">Then</span><br>            <span class="kwrd">Dim</span> queued(<span class="kwrd">Me</span>._pendingCommands.Count) <span class="kwrd">As</span> Command<br>            <span class="kwrd">Me</span>._pendingCommands.CopyTo(queued)<br>            <span class="kwrd">Me</span>.ProcessPendingCommands(queued)<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 for processing the commands themselves, there is one small hitch: what to do if connectivity disappears. Or, so you would think. Remember that if connectivity isn't present, the
<b>PageManager</b> detects it before handing commands off to the gateway, and just persists them. The actual processing of the commands is handled by a helper function, which allows for processing of commands to occur when network connectivity is restored to
 an already-running instance of the application, or to route the commands when a new session is started with existing connectivity. The helper function does nothing more than break up the
<b>Command</b> object and route it to the method responsible for routing commands to the
<b>BackPackGateway</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> ProcessPendingCommands(Command[] commands)<br>{<br>    <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 0; i &lt; commands.Length; i&#43;&#43;)<br>    {<br>        Command current = commands[i];<br>        <span class="kwrd">this</span>.InvokeOperation(current.Url, current.Arguments, current.Operation);<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> ProcessPendingCommands(<span class="kwrd">ByVal</span> commands() <span class="kwrd">As</span> Command)<br>    <span class="kwrd">Dim</span> i <span class="kwrd">As</span> <span class="kwrd">Integer</span> = 0<br>    <span class="kwrd">Do</span> <span class="kwrd">While</span> (i &lt; commands.Length)<br>        <span class="kwrd">Dim</span> current <span class="kwrd">As</span> Command = commands(i)<br>        <span class="kwrd">Me</span>.InvokeOperation(current.Url, current.Arguments, <br>            current.Operation)<br><br>        i = (i &#43; 1)<br>    <span class="kwrd">Loop</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>Because the code that handles the processing of the actual commands is asynchronous, and announces results by way of events and handlers, nothing more is needed. If the commands process successfully against the server, event handlers in the
<b>PageManager</b> and Winform will react accordingly. If there is a problem it will be passed along by the same event, and will be handled as needed by the
<b>PageManager</b> and UI. If connectivity somehow only &quot;flickered&quot; back on, and then quickly disappeared, the currently running command might run into serious problems (that's just the way of networked applications—though there is rollback functionality in
 place). However, subsequent pending commands will be routed into the <b>Invoke Operation()</b> method. Because that method checks for connectivity, and queues commands if there is no connectivity available, the commands will just be re-queued (and persisted
 as needed) until connectivity returns. </p>
<h4>Professional Driver; Closed Circuit</h4>
<p>With everything now in place, we're now ready for a full-blown test drive. While the UI is still a bit awkward around the whole 'sign in' process and my use of menus (I'm obviously not going to be putting
<a href="http://www.37signals.com/">37Signals</a> out of business with my app), it is still possible to take the entire app for a test drive and watch it work while on- and offline. I'd suggest something similar to the following (though any similar permutation
 should work fine): </p>
<ul>
<li>Build and deploy the application by pressing F5. </li><li>Enter your account name and API Key, then press the Log In button. (Save your Credentials so that you don't have to retype them by using the Credentials | Save menu option.)
</li><li>Load pages from the server (you'll need to be online for this, obviously) using the Pages menu.
</li><li>Make a few changes while online. Adding new objects should show you how <b>TreeNodes</b> will be briefly &quot;dirty&quot; until the change is approved on the server. (Modifying most other nodes happens to quickly to see most of the time—though changes to the title
 or name of a node won't be reflected in the UI until the change has been made on the server so that's a good way to see things in action.)
</li><li>Once you've played with the application online for a while, either go offline (disable your network connection somehow) or save your pages, close the application, and then go offline.
</li><li>With pages loaded, and while offline, make a few changes. You'll see that everything behaves as it did while online, only changes don't get marked as &quot;un-dirty&quot; immediately and newly added nodes aren't editable.
</li><li>At this point you can save your changes by closing the application and selecting Yes when prompted to save, or reconnect your network connection.
</li><li>If you simply recover your network connection (which will take the application a few seconds to notice), you'll start to see &quot;dirty&quot; nodes get replaced with their normal icons once they are updated on the server.
</li><li>If you closed and saved your changes, you'll see that upon opening the application, your pending nodes are still flagged as pending. Only once you reconnect will they be marked as clean, or unpending.
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/912387/BackPackAPI_Part4_3.gif"><img alt="Click here for larger image" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/912387/BackPackAPI_Part4_3_thumb.gif" width="420" border="0"></a>
</p>
<p><b>(click image to zoom)</b></p>
</li></ul>
<p>Taking the application for a spin is a definite hoot once you realize what is under the covers and what is going on. It's probably not quite ready to be handed off to your pointy-haired boss, or grandma, without some work; but there's a decent framework
 in place that will let you stub in the rest of the BackPack API functionality (such as tagging, linking, sharing, and duplicating pages) if you are so inclined. In other words, the application isn't really intended for resale. Rather, it's a sample application
 intended for developers—to help them get an idea of how to use XML to communicate back and forth with servers that use XML to communicate, and as their interface, as well as a chance to explore options for serialization and the dynamic generation of XML. In
 other words, it's been an excuse to code with XML for fun. </p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Michael-Campbell/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:c1ebce2a57f7484d80eb9e7600db2ff3">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-IV</comments>
      <itunes:summary>



&amp;nbsp;
This article is in series of BackPack API. This IV adds the ability to remove, or delete pages, notes, tasks, etc.



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






Previously on BackPack API...
Well, here we are: on the fourth and final installment of the articles on Xml4Fun dedicated to exploring the BackPack API. In the previous articles we&#39;ve covered a lot of ground. We covered the API itself in the first article, along with ways to translate
 user input into dynamically generated XML and pass data back and forth between our application and the BackPack servers. In the second article we took things a step further by creating an object model, using it to consume data expressed as XML, and configuring
 it so that it could consume that XML either from disk or from the web—all without any noticeable difference to our application. In the third article we examined the flow of information between our user interface, the middle tier, the BackPack servers, and
 then back out to the UI again (via the middle tier). We also added a TreeView control to visually represent our BackPack data, and loaded each
TreeNode&#39;s Tag property with a ResourceDescriptor object designed to allow for quick and easy lookups to the kind of data represented.
 
Remove/Delete
In previous articles, we&#39;ve worked on the basics of our object Model, but left out a key component: the ability to remove, or delete pages, notes, tasks, etc. Coding the functionality to remove objects is fairly straightforward, and just involves wiring
 up a bit of logic to our already existing infrastructure. Adding a new Context Menu item allows users to right-click and delete nodes.
 

 
When end users select the delete option, the node&#39;s Tag property is evaluated to determine what kind of node (Page, Task, Note, etc.) is being flagged for deletion. </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-IV</link>
      <pubDate>Tue, 31 Oct 2006 14:41:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-IV</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/912387_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/912387_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Michael Campbell</dc:creator>
      <itunes:author>Michael Campbell</itunes:author>
      <slash:comments>0</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Harnessing-the-BackPack-API-Part-IV/RSS</wfw:commentRss>
    </item>    
</channel>
</rss>