<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>craigweston</title>
	<atom:link href="http://www.craigweston.ca/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.craigweston.ca</link>
	<description>programming and web development</description>
	<pubDate>Mon, 05 Oct 2009 03:34:25 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Mount remote filesystems with SSHFS on OS X</title>
		<link>http://www.craigweston.ca/?p=171</link>
		<comments>http://www.craigweston.ca/?p=171#comments</comments>
		<pubDate>Mon, 05 Oct 2009 03:23:45 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[mac]]></category>

		<category><![CDATA[fuse]]></category>

		<category><![CDATA[macfuse]]></category>

		<category><![CDATA[remote]]></category>

		<category><![CDATA[sshfs]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=171</guid>
		<description><![CDATA[Most of my work is on the command line, if I need to grab a file from my media server I usually just scp, however today I decided to look into a easier method to mount my media server&#8217;s file system locally to my Macbook. If you are used to using Fuse on Linux, this [...]]]></description>
			<content:encoded><![CDATA[<p>Most of my work is on the command line, if I need to grab a file from my media server I usually just <a href="http://en.wikipedia.org/wiki/Secure_copy">scp</a>, however today I decided to look into a easier method to mount my media server&#8217;s file system locally to my Macbook. If you are used to using Fuse on Linux, this will seem familiar to you, as MacFuse is based upon Fuse.</p>
<p>This can be done with two nice tools, <a title="SSHFS" href="http://code.google.com/p/macfuse/wiki/MACFUSE_FS_SSHFS" target="_blank">SSHFS</a> and <a title="MacFuse" href="http://code.google.com/p/macfuse/" target="_blank">MacFuse</a>.</p>
<p>So first thing you will want to do is grab MacFuse and install it.</p>
<p>I&#8217;m currently using Snow Leopard, so I checked out SSHFS binaries with&#8230;</p>
<pre>svn co http://macfuse.googlecode.com/svn/trunk/filesystems/sshfs/binary sshfs-binaries
</pre>
<p>and grabbed the leopard version and moved it to my <em>/usr/bin</em></p>
<pre>mv sshfs-static-leopard /usr/bin/sshfs</pre>
<p>So at this point all the needed tools are setup, so to mount my media share on my server I can perform the following&#8230;.</p>
<pre>mkdir mediashare</pre>
<pre>sshfs craig@leafserver:/mediaserver/tv/ ./mediashare -oauto_cache,reconnect,volname=mediashare</pre>
<p>And now I have access to a my remote filesystem on both the command line and in Finder, with the ability to treat it as any local folder. Very handy I&#8217;d say. I plan on using this more often especially to manage some of the web servers I work on.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=171</wfw:commentRss>
		</item>
		<item>
		<title>Free some space on your Mac</title>
		<link>http://www.craigweston.ca/?p=163</link>
		<comments>http://www.craigweston.ca/?p=163#comments</comments>
		<pubDate>Thu, 07 May 2009 05:12:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[mac]]></category>

		<category><![CDATA[free]]></category>

		<category><![CDATA[freespace]]></category>

		<category><![CDATA[language]]></category>

		<category><![CDATA[mac apps]]></category>

		<category><![CDATA[storage]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=163</guid>
		<description><![CDATA[I just did a fresh install on my Macbook after picking up a new hard drive yesterday and was looking for some ways to minimize my system&#8217;s footprint as much as possible. While doing this I stumbled upon an application called Monolingual. Essentially it allows you to remove the loads of unnecessary language resources that are spread throughout your [...]]]></description>
			<content:encoded><![CDATA[<p>I just did a fresh install on my Macbook after picking up a new hard drive yesterday and was looking for some ways to minimize my system&#8217;s footprint as much as possible. While doing this I stumbled upon an application called <em><a href="http://monolingual.sourceforge.net/">Monolingual</a></em>. Essentially it allows you to remove the loads of unnecessary language resources that are spread throughout your system. It is really quite amazing when you start seeing the amount of foreign languages that are supported by default and would never be used by the average user. I was amazed at how much free space I gained after doing it, almost 2GB!</p>
<p>You can find the application <a href="http://monolingual.sourceforge.net/"><strong>here</strong></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=163</wfw:commentRss>
		</item>
		<item>
		<title>Skippy install - a task switcher for Xll</title>
		<link>http://www.craigweston.ca/?p=156</link>
		<comments>http://www.craigweston.ca/?p=156#comments</comments>
		<pubDate>Mon, 04 May 2009 05:17:43 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[skippy]]></category>

		<category><![CDATA[task-switcher]]></category>

		<category><![CDATA[xll]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=156</guid>
		<description><![CDATA[Im not a huge fan of taskbars, and being a Mac user as well has made me like Expose and the general task switcher idea  more. I stumbled upon a great little app today called Skippy which is great for getting similar functionality on my Linux machines. Here is a quick run down on [...]]]></description>
			<content:encoded><![CDATA[<p>Im not a huge fan of taskbars, and being a Mac user as well has made me like Expose and the general task switcher idea  more. I stumbled upon a great little app today called <a href="http://thegraveyard.org/skippy.php">Skippy</a> which is great for getting similar functionality on my Linux machines. Here is a quick run down on getting it installed and running on your <strong>Ubuntu</strong> system.<br />
First we need to get the <strong>Skippy</strong> source, which you can find <strong><a href="http://thegraveyard.org/skippy.php">here</a><a href="http://thegraveyard.org/files/skippy-0.5.0.tar.bz2">.</a></strong></p>
<p>Once you have the source, you will want to ensure you have all the requirements installed. Luckily this can all be taken from the <strong>Ubuntu</strong> repos.</p>
<pre>
$ sudo apt-get install xorg-dev
$ sudo apt-get install libxft-dev
$ sudo apt-get install libimlib2-dev
</pre>
<p>Now untar the Skippy source we downloaded.</p>
<pre>$ tar -xjvf skippy-0.5.0.tar.bz2</pre>
<p>You should be able to now call make and build the <strong>Skippy</strong> binary. Once the compile finishes you will need to copy over the default <strong>Skippy</strong> configuration file into your home directory.</p>
<pre>$ cp skippyrc-default /home/craig/.skippyrc</pre>
<p>And now you can start <strong>Skippy</strong> and invoke it with its default key binding being F11.</p>
<p>Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=156</wfw:commentRss>
		</item>
		<item>
		<title>Getting XMMS2 installed on Ubuntu</title>
		<link>http://www.craigweston.ca/?p=146</link>
		<comments>http://www.craigweston.ca/?p=146#comments</comments>
		<pubDate>Wed, 08 Apr 2009 03:53:53 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Linux]]></category>

		<category><![CDATA[audio]]></category>

		<category><![CDATA[ubuntu]]></category>

		<category><![CDATA[xmms2]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=146</guid>
		<description><![CDATA[XMMS2 is the successor to the XMMS, a great all around media player for Linux. Unlike XMMS, XMMS2 incorporates a client server model, acting as a daemon for client applications to use as their back end. I however prefer just to control it directly from the command line and therefore i find it perfect. The [...]]]></description>
			<content:encoded><![CDATA[<p>XMMS2 is the successor to the XMMS, a great all around media player for Linux. Unlike XMMS, XMMS2 incorporates a client server model, acting as a daemon for client applications to use as their back end. I however prefer just to control it directly from the command line and therefore i find it perfect. The less GUI apps I have open the better!</p>
<p>Here is how to get XMMS2 running on Ubuntu with a bunch of useful plug-ins.<br />
Install the app&#8230;</p>
<pre> sudo apt-get install xmms2</pre>
<p>Install the plug-ins&#8230;</p>
<pre>sudo apt-get install xmms2-plugin-all</pre>
<p>Launch the daemon&#8230;</p>
<pre>xmms2-launcher</pre>
<p>From this point the xmms2 deamon is now running and you can control it via the xmms2 command. I prefer to store all my media on a separate ubuntu server here at my home. On that server I run another great application called gnump3d, which allows me to stream all my music over my LAN keeping my desktop clean and tidy. The playlists that get provided from <a href="http://www.gnu.org/software/gnump3d/">gnump3d</a> come in the form of .m3u files. To get this to play with xmms2 you need the<em> xmms-plugin-m3u</em> plugin which comes with the<em> xmms2-plugin-all</em> we installed above. In order to load an m3u play-list we use the <em>addpls</em> command as shown below.</p>
<pre>xmms2 addpls recurse.m3u</pre>
<p>now that the playlist is loaded we need to play it</p>
<pre>xmms2 play</pre>
<p>And if the song happens to not be so great we can skip it with&#8230;</p>
<pre>xmms2 next</pre>
<p>And so on..</p>
<p>There are many other useful commands&#8230;to see a quick list just type
<pre>xmms2</pre>
<p> without any other commands.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=146</wfw:commentRss>
		</item>
		<item>
		<title>Overriding checkbox behaviour adding a confirm popup</title>
		<link>http://www.craigweston.ca/?p=139</link>
		<comments>http://www.craigweston.ca/?p=139#comments</comments>
		<pubDate>Tue, 16 Dec 2008 03:27:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[ASP]]></category>

		<category><![CDATA[checkbox]]></category>

		<category><![CDATA[hacks]]></category>

		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=139</guid>
		<description><![CDATA[I recently needed to add a confirm dialog for an asp checkbox. The confirm popup should determine whether the checkbox is posted back to the server or returned to its original state. Merely adding a onclick=&#8221;return confirm(&#8217;blah blah&#8217;)&#8221; here will not work because the post back will never occur (see why below). Because of this [...]]]></description>
			<content:encoded><![CDATA[<p>I recently needed to add a confirm dialog for an asp checkbox. The confirm popup should determine whether the checkbox is posted back to the server or returned to its original state. Merely adding a <em>onclick=&#8221;return confirm(&#8217;blah blah&#8217;)&#8221;</em> here will not work because the post back will never occur (see why below). Because of this I whipped up this quick easy hack that I will share with you.</p>
<p>I defined a typical checkbox that auto post backs when its change event occurs:</p>
<pre name="code" class="javascript">

&lt;asp:CheckBox AutoPostBack=&quot;true&quot; Text=&quot;Status&quot; ID=&quot;chkExample&quot; runat=&quot;server&quot; OnCheckedChanged=&quot;OnCheckedChangeLabel&quot; /&gt;
</pre>
<p>The markup that is generated for us by asp then looks like this:</p>
<pre name="code" class="javascript">
&lt;input id=&quot;chkExample&quot; type=&quot;checkbox&quot; name=&quot;chkExample&quot; checked=&quot;checked&quot; onclick=&quot;javascript:setTimeout(&#039;__doPostBack(\&#039;chkExample\&#039;,\&#039;\&#039;)&#039;, 0)&quot; /&gt;
</pre>
<p>So essentially what we want to do is bypass this <em>__doPostBack</em> call so that we can post back only when our confirm popup returns true, so lets write a javascript function to do just that&#8230;</p>
<pre name="code" class="javascript">
    &lt;script type=&quot;text/javascript&quot;&gt;

        function OverrideCheckPostback() {
            if (confirm(&quot;Are you sure?&quot;)) {
                __doPostBack(&#039;chkExample&#039;, &#039;&#039;);
                return true;
            }
            else
                return false;
        }
    &lt;/script&gt;
</pre>
<p>And then in our <em>PageLoad</em> we add the <em>onclick</em> attribute and specify the our function to be called.</p>
<pre name="code" class="csharp">
    protected void Page_Load(object sender, EventArgs e)
    {
        chkExample.Attributes.Add(&quot;onclick&quot;, &quot;return OverrideCheckPostback();&quot;);
    }
</pre>
<p>Now lets look at the code that gets generated for us. As we can see the original generated post back call is still there, but will never be called because we return before it has a chance while returning the value of our confirm popup. The post back is now handled in our own function only when <em>confirm() </em>returns true (aka the user presses &#8216;OK&#8217;).</p>
<pre name="code" class="javascript">

&lt;input id=&quot;chkExample&quot; type=&quot;checkbox&quot; name=&quot;chkExample&quot; onclick=&quot;return OverrideCheckPostback();setTimeout(&#039;__doPostBack(\&#039;chkExample\&#039;,\&#039;\&#039;)&#039;, 0)&quot; /&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=139</wfw:commentRss>
		</item>
		<item>
		<title>Double click AJAX Accordion bug</title>
		<link>http://www.craigweston.ca/?p=119</link>
		<comments>http://www.craigweston.ca/?p=119#comments</comments>
		<pubDate>Sat, 13 Dec 2008 04:00:46 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[ASP]]></category>

		<category><![CDATA[accordion bug]]></category>

		<category><![CDATA[ajax bugs]]></category>

		<category><![CDATA[double click]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=119</guid>
		<description><![CDATA[This post will be a short one summarizing a work around for the double click problem associated with the accordion control from the ASP.NET Ajax Control Toolkit. This problem occurs when controls are placed within the panes of the accordion control. When the page is loaded it takes two clicks of the control before the [...]]]></description>
			<content:encoded><![CDATA[<p>This post will be a short one summarizing a work around for the double click problem associated with the accordion control from the ASP.NET Ajax Control Toolkit. This problem occurs when controls are placed within the panes of the accordion control. When the page is loaded it takes two clicks of the control before the actual click event will be invoked.</p>
<p>Lets recreate an example to demonstrate and recreate this problem. First we will create an accordion and assign a button and label within its content template. The label we will use to test when our event is actually invoked. I will use my previous post&#8217;s books catalog example for this.</p>
<pre name="code" class="csharp">
        &lt;ajaxToolkit:Accordion
            ID=&quot;accordionBooks&quot;
            runat=&quot;server&quot;
            SelectedIndex=&quot;0&quot;
            HeaderCssClass=&quot;accordionHeader&quot;
            HeaderSelectedCssClass=&quot;accordionHeaderSelected&quot;
            ContentCssClass=&quot;accordionContent&quot;
            FadeTransitions=&quot;false&quot;
            FramesPerSecond=&quot;40&quot;
            TransitionDuration=&quot;250&quot;
            AutoSize=&quot;None&quot;
            RequireOpenedPane=&quot;false&quot;
            SuppressHeaderPostbacks=&quot;true&quot;
            onitemdatabound=&quot;accordionBooks_ItemDataBound&quot;&gt;

                &lt;HeaderTemplate&gt;
                    &lt;p&gt;
                        &lt;asp:Literal ID=&quot;litCategory&quot; runat=&quot;server&quot; Text=&quot;Category:&quot; /&gt;
                        &lt;asp:Label ID=&quot;lblBookCategory&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;category_name&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                    &lt;/p&gt;
                &lt;/HeaderTemplate&gt;

                &lt;ContentTemplate&gt;

                    &lt;asp:HiddenField ID=&quot;hdnCategoryId&quot; Value=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;id&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;

                    &lt;asp:Label ID=&quot;lblInvokeStatus&quot; Text=&quot;Not Invoked&quot; runat=&quot;server&quot; /&gt;
                    &lt;asp:Button ID=&quot;btnInvokeEvent&quot; runat=&quot;server&quot; Text=&quot;Invoke Event&quot; OnClick=&quot;OnClickInvoke&quot; /&gt;
                &lt;/ContentTemplate&gt;
            &lt;/ajaxToolkit:Accordion&gt;
</pre>
<p>And the code behind event&#8230;</p>
<pre name="code" class="csharp">
    protected void OnClickInvoke(object sender, EventArgs e)
    {
        Label invokeLabel = (Label)
            accordionBooks.Panes[accordionBooks.SelectedIndex].FindControl(&quot;lblInvokeStatus&quot;);

        invokeLabel.Text = &quot;Invoked!&quot;;
    }
</pre>
<p>Now, if you were to run the above code on a databound accordion you should see the double click problem occuring. The label will not change until the second click, but after that it will work each consecutive time.</p>
<p>So what I will now do is fake the button click, by applying our asp button outside our accordion where it will not be affected, and then force its click event from a button within the accordion using some javascript.</p>
<pre name="code" class="csharp">
        &lt;asp:Button ID=&quot;btnInvokeEvent&quot; runat=&quot;server&quot; Text=&quot;Invoke Event&quot; OnClick=&quot;OnClickInvoke&quot; /&gt;

        &lt;ajaxToolkit:Accordion
            ID=&quot;accordionBooks&quot;
            runat=&quot;server&quot;
            SelectedIndex=&quot;0&quot;
            HeaderCssClass=&quot;accordionHeader&quot;
            HeaderSelectedCssClass=&quot;accordionHeaderSelected&quot;
            ContentCssClass=&quot;accordionContent&quot;
            FadeTransitions=&quot;false&quot;
            FramesPerSecond=&quot;40&quot;
            TransitionDuration=&quot;250&quot;
            AutoSize=&quot;None&quot;
            RequireOpenedPane=&quot;false&quot;
            SuppressHeaderPostbacks=&quot;true&quot;
            onitemdatabound=&quot;accordionBooks_ItemDataBound&quot;&gt;

                &lt;HeaderTemplate&gt;
                    &lt;p&gt;
                        &lt;asp:Literal ID=&quot;litCategory&quot; runat=&quot;server&quot; Text=&quot;Category:&quot; /&gt;
                        &lt;asp:Label ID=&quot;lblBookCategory&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;category_name&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                    &lt;/p&gt;
                &lt;/HeaderTemplate&gt;

                &lt;ContentTemplate&gt;

                    &lt;asp:HiddenField ID=&quot;hdnCategoryId&quot; Value=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;id&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;

                    &lt;asp:Label ID=&quot;lblInvokeStatus&quot; Text=&quot;Not Invoked&quot; runat=&quot;server&quot; /&gt;
                    &lt;input type=&quot;button&quot; value=&quot;Invoke Event&quot; onclick=&quot;javascript:$get(&#039;&lt;%= btnInvokeEvent.UniqueID %&gt;&#039;).click();&quot; /&gt;

                &lt;/ContentTemplate&gt;
            &lt;/ajaxToolkit:Accordion&gt;
</pre>
<p>And now the click event should fire on the first click. When I tested this on an accordion with the panes hardcoded the bug didn&#8217;t show up, so it is likely that you will not need to use this workaround unless you are data binding your accordion. Hope this helped.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=119</wfw:commentRss>
		</item>
		<item>
		<title>AJAX Toolkit: Accordion control with nested gridview</title>
		<link>http://www.craigweston.ca/?p=108</link>
		<comments>http://www.craigweston.ca/?p=108#comments</comments>
		<pubDate>Fri, 12 Dec 2008 03:31:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[ASP]]></category>

		<category><![CDATA[Accordion]]></category>

		<category><![CDATA[Ajax toolkit]]></category>

		<category><![CDATA[Nested Data]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=108</guid>
		<description><![CDATA[The accordion control is a great control to add both effect and functionality to your ASP.NET Ajax enabled site. It presents data in a sleek way and allows for good use of screen space only showing you what you really need to see in a parent child fashion.
Today I am going to demonstrate the ability of [...]]]></description>
			<content:encoded><![CDATA[<p>The accordion control is a great control to add both effect and functionality to your ASP.NET Ajax enabled site. It presents data in a sleek way and allows for good use of screen space only showing you what you really need to see in a parent child fashion.</p>
<p>Today I am going to demonstrate the ability of nesting gridviews within an accordion control. This will allow you to map and display 1..* relationships in an efficient and logical way. In future posts I will also be showing how to extend this to use the modal popup control to allow easy editing of the data.</p>
<p>The example I am using is a simple books catalog database, where books are mapped to their related category. Here is the SQL for generating the database table structure;</p>
<pre name="code" class="sql">
DROP TABLE Book;
DROP TABLE BookCategory;

CREATE TABLE BookCategory (
	id					INT IDENTITY(1,1) PRIMARY KEY,
	category_name		VARCHAR(25) NOT NULL
);

CREATE TABLE Book (
	id					INT IDENTITY(1,1) PRIMARY KEY,
	title				VARCHAR(50) NOT NULL,
	publisher			VARCHAR(25) NOT NULL,
	ISBN				VARCHAR(10) NOT NULL,
	category_id			INT REFERENCES BookCategory(id)
);
</pre>
<p>Assuming you have the <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/samples/Default.aspx">AJAX ASP.NET Control Toolkit</a> installed the first thing will be too add an accordion control to your page. Define both a header and content section within the accordion. These templates will allow you to customize how the data is displayed. The header will represent our parent record details and when expanded the gridview will present the many rows associated to it.</p>
<pre name="code" class="csharp">
        &lt;asp:ScriptManager ID=&quot;ScriptManager&quot; runat=&quot;server&quot;&gt;
        &lt;/asp:ScriptManager&gt;

        &lt;ajaxToolkit:Accordion
            ID=&quot;accordionBooks&quot;
            runat=&quot;server&quot;
            SelectedIndex=&quot;0&quot;
            HeaderCssClass=&quot;accordionHeader&quot;
            HeaderSelectedCssClass=&quot;accordionHeaderSelected&quot;
            ContentCssClass=&quot;accordionContent&quot;
            FadeTransitions=&quot;false&quot;
            FramesPerSecond=&quot;40&quot;
            TransitionDuration=&quot;250&quot;
            AutoSize=&quot;None&quot;
            RequireOpenedPane=&quot;false&quot;
            SuppressHeaderPostbacks=&quot;true&quot;
            onitemdatabound=&quot;accordionBooks_ItemDataBound&quot;&gt;

                &lt;HeaderTemplate&gt;
                    &lt;p&gt;
                        &lt;asp:Literal ID=&quot;litCategory&quot; runat=&quot;server&quot; Text=&quot;Category:&quot; /&gt;
                        &lt;asp:Label ID=&quot;lblBookCategory&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;category_name&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                    &lt;/p&gt;
                &lt;/HeaderTemplate&gt;

                &lt;ContentTemplate&gt;

                    &lt;asp:HiddenField ID=&quot;hdnCategoryId&quot; Value=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;id&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;

                    &lt;asp:GridView
                    ID=&quot;gvBooks&quot;
                    runat=&quot;server&quot;
                    DataKeyNames=&quot;Id&quot;
                    AutoGenerateColumns=&quot;false&quot;
                    Width=&quot;100%&quot;&gt;

                        &lt;Columns&gt;
                            &lt;asp:BoundField DataField=&quot;id&quot; runat=&quot;server&quot; /&gt;
                            &lt;asp:TemplateField&gt;
                                &lt;ItemTemplate&gt;
                                    &lt;asp:Label ID=&quot;lblTitle&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;Title&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                                &lt;/ItemTemplate&gt;
                            &lt;/asp:TemplateField&gt;

                            &lt;asp:TemplateField&gt;
                                &lt;ItemTemplate&gt;
                                    &lt;asp:Label ID=&quot;lblPublisher&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;Publisher&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                                &lt;/ItemTemplate&gt;
                            &lt;/asp:TemplateField&gt;

                            &lt;asp:TemplateField&gt;
                                &lt;ItemTemplate&gt;
                                    &lt;asp:Label ID=&quot;lblISBN&quot; Text=&#039;&lt;%# DataBinder.Eval(Container.DataItem, &quot;ISBN&quot;) %&gt;&#039; runat=&quot;server&quot; /&gt;
                                &lt;/ItemTemplate&gt;
                            &lt;/asp:TemplateField&gt;

                        &lt;/Columns&gt;
                    &lt;/asp:GridView&gt;
                &lt;/ContentTemplate&gt;
            &lt;/ajaxToolkit:Accordion&gt;
</pre>
<p>Above you can see that we bind our category name to our header template. The content template then contains the gridview which contains the details of each book.</p>
<p>Essentially we will be binding our data in two steps. On page load we will bind our accordion to the book categories from our &#8216;BookCategory&#8217; table. The category name will be assigned to the label within the header template. The Id of the category will be stored in a hidden field within the content template. This will allow us to get the id needed to be able to bind our books gridview by category type later in the &#8216;item data bound&#8217; event.</p>
<pre name="code" class="csharp">
    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            accordionBooks.DataSource = BookDB.GetAllBookCategories().Tables[0].DefaultView;
            accordionBooks.DataBind();
        }
        catch
        {
            DisplayError(&quot;Error while getting data&quot;);
        }
    }
</pre>
<p>Note that we are using the default view here. While writing this post I forgot this step and couldn&#8217;t figure out why I was getting no data showing up. You cannot assign the data source a data table or dataset, however generic list collections seem to bind fine.</p>
<p>The second step to binding is using the the item data bound event, which allows us to bind our data to our gridview as we move through each accordion item. We need to perform a check for item type within this function because it is executed for both header and content sections. We obviously want the content section. We also use the AccordionItemEventArgs to get the current accordion item so that we can find the gridview and hidden field controls and reference them specifically. We then extract the id, perform a database query and bind the gridview with the books related to that category.</p>
<pre name="code" class="csharp">
    protected void accordionBooks_ItemDataBound(object sender, AjaxControlToolkit.AccordionItemEventArgs e)
    {
        try
        {
            if (e.ItemType == AjaxControlToolkit.AccordionItemType.Content)
            {
                GridView gdvBooks = (GridView)e.AccordionItem.FindControl(&quot;gvBooks&quot;);
                HiddenField hdnCategoryId = (HiddenField)e.AccordionItem.FindControl(&quot;hdnCategoryId&quot;);

                int categoryId;
                if (!int.TryParse(hdnCategoryId.Value, out categoryId))
                    throw new Exception(&quot;Unable to parse id&quot;);

                gdvBooks.DataSource = BookDB.GetAllBooksByCategoryId(categoryId);
                gdvBooks.DataBind();
            }
        }
        catch
        {
            DisplayError(&quot;Error while getting data&quot;);
        }
    }
</pre>
<p>And that is all that is there is to it. I have included my database code below for those who are interested as well as the stored procedures.</p>
<pre name="code" class="csharp">
	public static DataSet GetAllBooksByCategoryId(int categoryId)
	{
        DataSet ds = null;
        try
        {
            using (SqlConnection conn = new SqlConnection(&quot;Data Source=LEAF-DEV\\SQLEXPRESS;Initial Catalog=BookCatalog;Integrated Security=SSPI;&quot;))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(&quot;spGetBooksByCategory&quot;, conn))
                {
                    cmd.Parameters.Add(&quot;@category_id&quot;, SqlDbType.Int).Value = categoryId;
                    cmd.CommandType = CommandType.StoredProcedure;

                    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                    {
                        ds = new DataSet();
                        da.Fill(ds);
                    }
                }
            }
        }
        catch(Exception ex)
        {
            throw ex;
        }
        return ds;
	}

    public static DataSet GetAllBookCategories()
    {
        DataSet ds = null;
        try
        {
            using (SqlConnection conn = new SqlConnection(&quot;Data Source=LEAF-DEV\\SQLEXPRESS;Initial Catalog=BookCatalog;Integrated Security=SSPI;&quot;))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(&quot;spGetBookCategories&quot;, conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                    {
                        ds = new DataSet();
                        da.Fill(ds);
                        int rowCount = ds.Tables[0].Rows.Count;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return ds;
    }
</pre>
<pre name="code" class="sql">
USE BookCatalog;
DROP PROCEDURE spGetBookCategories;
DROP PROCEDURE spGetBooksByCategory;

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE spGetBookCategories
AS
BEGIN
	SELECT category_name, id
	FROM BookCategory
END
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE spGetBooksByCategory(@category_id INT)
AS
BEGIN
	SELECT
		id,
		title,
		publisher,
		ISBN,
		category_id
	FROM Book
	WHERE category_id = @category_id
END
GO
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=108</wfw:commentRss>
		</item>
		<item>
		<title>Generating fast test data in SQL Server</title>
		<link>http://www.craigweston.ca/?p=69</link>
		<comments>http://www.craigweston.ca/?p=69#comments</comments>
		<pubDate>Wed, 08 Oct 2008 01:37:13 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[SQL]]></category>

		<category><![CDATA[Databases]]></category>

		<category><![CDATA[SQL Server]]></category>

		<category><![CDATA[Test Scripts]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=69</guid>
		<description><![CDATA[Here is a quick and easy way to insert data into multiple tables joined by a foreign key constraint using only a SQL script.
I use this method often when I need to generate install scripts with static data or reusable and easily generated test data.
The method below uses the SQL Server @@identity variable to grab [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a quick and easy way to insert data into multiple tables joined by a foreign key constraint using only a SQL script.</p>
<p>I use this method often when I need to generate install scripts with static data or reusable and easily generated test data.</p>
<p>The method below uses the SQL Server @@identity variable to grab the last inserted id, assigning it to a temporary variable, and allowing it to be used in the second table to perform multiple row additions, linking each new row back to the parent record.</p>
<p>Without assigning it to a temporary variable as you will see below, the @@identity variable would reflect each new child row each time we did an insert, preventing us from linking the child rows back to our parent table.</p>
<pre name="code" class="sql">

DECLARE @fk_user INT;
DECLARE @fk_admin_role INT;
DECLARE @fk_user_role INT;

-- insert a user --
INSERT INTO users (username, password, firstname, lastname) VALUES(&#039;user_bill&#039;, &#039;password&#039;, &#039;billy&#039;, &#039;west&#039;);
SET @fk_user = @@identity;

-- insert some roles --
INSERT INTO roles (role_name) VALUES(&#039;user&#039;);
SET @fk_user_role = @@identity;

INSERT INTO roles (role_name) VALUES(&#039;admin&#039;);
SET @fk_admin_role = @@identity;

-- now populate the many to many table, with foreign keys from the stored values --
INSERT INTO users_roles (role_id, user_id) VALUES(@fk_user_role, @fk_user);
INSERT INTO users_roles(role_id, user_id) VALUES(@fk_admin_role, @fk_user);
</pre>
<p>The above now provides us with a script to quickly generate a basic multi role user, that we could use in a install script for our app or test script. We could now reload the data over and over again without needing to worry about specific primary keys and matching foreign keys, it is all done dynamically.</p>
<p>Each time we perform a insert we retrieve the last inserted primary key value and store it in a temporary variable. We then use these variables to combine and link our records via the &#8220;users_roles&#8221; table at the end once the required roles have been inserted.</p>
<p>[user] &lt;&#8211; [users_roles] &#8211;&gt;  [roles]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=69</wfw:commentRss>
		</item>
		<item>
		<title>Helvetica</title>
		<link>http://www.craigweston.ca/?p=55</link>
		<comments>http://www.craigweston.ca/?p=55#comments</comments>
		<pubDate>Thu, 02 Oct 2008 00:25:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[Design]]></category>

		<category><![CDATA[Type]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=55</guid>
		<description><![CDATA[Not that its really programming related, but still web development related, I discovered this article today randomly which sparked my need to blog it.

http://www.iht.com/articles/2007/03/30/arts/design2.php

Font is one of the key things I pay attention too. I will spend a lot of time trying many fonts before I get something I am satisfied with, and usually in [...]]]></description>
			<content:encoded><![CDATA[<p>Not that its really programming related, but still web development related, I discovered this article today randomly which sparked my need to blog it.<br />
<br />
<a href="http://www.iht.com/articles/2007/03/30/arts/design2.php">http://www.iht.com/articles/2007/03/30/arts/design2.php</a><br />
</p>
<p>Font is one of the key things I pay attention too. I will spend a lot of time trying many fonts before I get something I am satisfied with, and usually in the end it is Helvetica.  It has always been my favorite typeface, and because of this you will see it used in most of my web and logo design work.  The logo used for this blog is actually a Helvetica Thin font. </p>
<p>Helvetica is so common amongst many areas of design and art that once you begin to use it heavily, you will also begin to notice it more in advertising, marketing material, even on your cereal box in the morning. Everywhere you go Helvetica is there, making it one of the most universal fonts in my opinion. It is very simple, yet very powerful and because of this is often used on its own with little graphical help. Minimalism design, presently a popular design trend on the web, makes heavy use of this simplicity/power relationship that Helvetica produces. </p>
<p>Below are some key points I have found beneficial when working with this font. I have also whipped up a quick example of the uses.</p>
<ul>
<li>In most cases it looks best with a very small letter spacing</li>
<li>The bigger the better, especially when used with smaller complementary text</li>
<li>Great for minimalism design</li>
</ul>
<p><img src="/images/helvetica_tribute.png" alt="Helvetica Tribute" /></p>
<p>Now I suggest you load photoshop, select Helvetica and play.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=55</wfw:commentRss>
		</item>
		<item>
		<title>Gridview ObjectDataSource binding with multiple tiers</title>
		<link>http://www.craigweston.ca/?p=44</link>
		<comments>http://www.craigweston.ca/?p=44#comments</comments>
		<pubDate>Sun, 28 Sep 2008 17:11:09 +0000</pubDate>
		<dc:creator>admin</dc:creator>
		
		<category><![CDATA[ASP]]></category>

		<guid isPermaLink="false">http://www.craigweston.ca/?p=44</guid>
		<description><![CDATA[Binding a DataSource control to a gridview is a understandable way of grabbing data from your database and presenting it to the end user. However when building enterprise style applications it is often best to use a multi layer approach, usually consisting of a user layer, business logic layer, and data layer. Having a datasource [...]]]></description>
			<content:encoded><![CDATA[<p>Binding a DataSource control to a gridview is a understandable way of grabbing data from your database and presenting it to the end user. However when building enterprise style applications it is often best to use a multi layer approach, usually consisting of a user layer, business logic layer, and data layer. Having a datasource directly connected and pulling data from the database does not really make as much sense in this style application especially if there is some logic that needs to be performed in the business layer before hand. This is where the value of the ObjectDataSource comes in. It allows you to use objects as your data source, providing you with the task of coding the functionality for pulling down the data. </p>
<p>What I will demonstrate below will be a simple use of a ObjectDataSource for simply pulling data from the database using the &#8220;select method&#8221; attribute.</p>
<p>Here is what our user layer source will look like.</p>
<pre name="code" class="xhtml">

&lt;asp:ObjectDataSource
    TypeName=&quot;UserLib.User&quot;
    SelectMethod=&quot;GetAll&quot;
    ID=&quot;odsUsers&quot;
    runat=&quot;server&quot;
/&gt;

&lt;asp:GridView ID=&quot;gvUsers&quot; DataSourceID=&quot;odsUsers&quot; runat=&quot;server&quot;
    AutoGenerateColumns=&quot;False&quot;&gt;
    &lt;Columns&gt;
        &lt;asp:TemplateField HeaderText=&quot;Username&quot;&gt;
            &lt;ItemTemplate&gt;
                &lt;asp:Label ID=&quot;lblUsernameRow&quot; runat=&quot;server&quot; Text=&#039;&lt;%# Bind(&quot;username&quot;) %&gt;&#039;/&gt;
            &lt;/ItemTemplate&gt;
            &lt;EditItemTemplate&gt;
                &lt;asp:TextBox ID=&quot;lblUsernameRow&quot; runat=&quot;server&quot; Text=&#039;&lt;%# Bind(&quot;username&quot;) %&gt;&#039;&gt;&lt;/asp:TextBox&gt;
            &lt;/EditItemTemplate&gt;
        &lt;/asp:TemplateField&gt;
    &lt;/Columns&gt;
&lt;/asp:GridView&gt;
</pre>
<p>So lets pull this apart. We define a object data source, specifying two important attributes &#8220;select method&#8221; and  &#8220;typename&#8221;. The select method specifies the method which we want to call on our object to get our data. This method must return an object of IEnumerable or ICollection, so we can return a DataSet. The typename specifies the object that we will call the method on.</p>
<p>In the gridview we bind the datasource by specifying the &#8220;datasourceID&#8221; attribute and giving it the ID of our object datasource.</p>
<pre name="code" class="csharp">

public DataSet GetAll()
{
    DataSet ds = null;
    try
    {
        UserData.User data = new UserData.User();
        ds = data.GetAll();
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return ds;
}
</pre>
<p>Above is our business logic layer. Theres really no logic here, all we are doing is calling to our data layer to grab the data from the database and load it into a dataset for us. When we receive the dataset from the data layer we will then pass this dataset back to the user layer to be binded to the gridview.</p>
<pre name="code" class="csharp">

        public DataSet GetAll()
        {
            SqlConnection conn  = null;
            SqlDataAdapter da   = null;
            SqlCommand cmd      = null;
            DataSet ds = null;

            try
            {
                conn = new SqlConnection(CONN_STRING);
                conn.Open();

                ds = new DataSet();

                cmd = new SqlCommand();
                cmd.Connection = conn;
                cmd.CommandText = &quot;spGetAllUsers&quot;;
                cmd.CommandType = CommandType.StoredProcedure;

                da = new SqlDataAdapter(cmd);
                da.Fill(ds, &quot;users&quot;);

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (conn != null &amp;&amp; conn.State == ConnectionState.Open)
                {
                    conn.Close();
                    conn.Dispose();
                }

                if (cmd != null)
                    cmd.Dispose();
                if (da != null)
                    da.Dispose();
            }
            return ds;
        }
</pre>
<p>Here is our data layer method which does all of our database interactions.</p>
<p>Today I only demonstrated the select method, but updates, deletes and inserts can also be setup and performed by the ObjectDataSource making it a very powerful and customizable way of interacting with the database.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.craigweston.ca/?feed=rss2&amp;p=44</wfw:commentRss>
		</item>
	</channel>
</rss>
