<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>www.hackification.com &#187; Tutorials</title>
	<atom:link href="http://www.hackification.com/category/tutorials/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hackification.com</link>
	<description></description>
	<lastBuildDate>Sat, 05 Jun 2010 11:16:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Quick Tip: Avoid Enums If Possible</title>
		<link>http://www.hackification.com/2009/12/01/quick-tip-avoid-enums-if-possible/</link>
		<comments>http://www.hackification.com/2009/12/01/quick-tip-avoid-enums-if-possible/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 18:16:43 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Opinion]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[architecture]]></category>
		<category><![CDATA[enums]]></category>
		<category><![CDATA[oo]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=330</guid>
		<description><![CDATA[One of the &#8220;anti-patterns&#8221; I come across from time to time is over-use of enumerations for control flow. This article describes why I consider it an anti-pattern, and how to counteract it. Let&#8217;s suppose we want to represent an arithmetic operation on two numbers &#8211; such as plus, minus, multiply, etc. We could represent that [...]]]></description>
			<content:encoded><![CDATA[<p>One of the &#8220;anti-patterns&#8221; I come across from time to time is over-use of enumerations for control flow. This article describes why I consider it an anti-pattern, and how to counteract it.</p>
<p><span id="more-330"></span>Let&#8217;s suppose we want to represent an arithmetic operation on two numbers &#8211; such as plus, minus, multiply, etc. We could represent that operation as an enum (although to be clear &#8211; I don&#8217;t think you should):</p>
<pre>enum ArithmeticOperation
{
  Add,
  Subtract,
  Multiply,
  Divide
}</pre>
<p>We could then define a function to apply this operation to two numbers (highlighting will be explained later):</p>
<pre>int ApplyOperation(ArithmeticOperation op, int x, int y)
{
  switch(op)
  {
    <span style="color: #ffff00;">case ArithmeticOperation.Add: return x + y;</span>
    case ArithmeticOperation.Subtract: return x - y;
    case ArithmeticOperation.Multiply: return x * y;
    case ArithmeticOperation.Divide: return x / y;
    default: throw new InvalidOperationException();
  }
}</pre>
<p>That&#8217;s&#8230; sort of fine &#8211; but what happens when we want to extend it?</p>
<p><strong>Adding Operators: No Compile-Time Checking</strong></p>
<p>Let&#8217;s consider what happens if we want to add another operator &#8211; say exponentiation. If we add the enum value but forget to implement the switch case value, everything compiles fine. It&#8217;s only once we come to run the code, and actually hit that code path, that we discover the mistake, giving a run-time exception.</p>
<p><strong>Adding Methods: Bad Code Organisation</strong></p>
<p>Next, imagine what happens if we need to add more methods that switch on this enum. We might need a method returning the operator symbol, and another returning the operator precedence.</p>
<pre>string GetOperatorSymbol(ArithmeticOperation op)
{
  switch(op)
  {
    <span style="color: #ffff00;">case ArithmeticOperation.Add: return "+";</span>
    case ArithmeticOperation.Subtract: return "-";
    case ArithmeticOperation.Multiply: return "*";
    case ArithmeticOperation.Divide: return "/";
    default: throw new InvalidOperationException();
  }
}

int GetOperatorPrecedence(ArithmeticOperation op)
{
  switch(op)
  {
    <span style="color: #ffff00;">case ArithmeticOperation.Add: return 10;</span>
    case ArithmeticOperation.Subtract: return 10;
    case ArithmeticOperation.Multiply: return 20;
    case ArithmeticOperation.Divide: return 20;
    default: throw new InvalidOperationException();
  }
}</pre>
<p>I&#8217;ve highighted the relevant code for the &#8220;add&#8221; operator. Notice how it&#8217;s spread all over the place. Switch statements might group by operation, but they split by concept &#8211; and that&#8217;s the exact opposite of what&#8217;s usually intended with OO coding.</p>
<p><strong>A Better Way</strong></p>
<p>I&#8217;d suggest a better way of approaching this problem is to use an abstract class.</p>
<pre>abstract class ArithmeticOperation
{
  abstract int ApplyOperation(int x, int y);
  abstract string GetSymbol();
  abstract int GetPrecendence();
}

class AddArithmeticOperation : ArithmeticOperation
{
  override int ApplyOperation(int x, int y)
  {
    return x + y;
  }

  override string GetSymbol()
  {
    return "+";
  }

  override int GetPrecedence()
  {
    return 10;
  }
}

// ...and so forth for the other operators.</pre>
<p>That way, all the code for each operator sits in the same place, and adding any new methods for an operator requires all operators to be implemented before the code will even compile.</p>
<p><strong>When to Use Enums</strong></p>
<p>So if enums should be avoided, why do most languages include them? Personally I&#8217;d be happy without them,  but I can think of one possible reason you might want to use an enum. If you&#8217;re defining a public interface designed for consumption by other coders, you could argue that simplifying the interface at the expense of the code inside is a valid trade-off.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/12/01/quick-tip-avoid-enums-if-possible/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Resizing Single-Image-Rollovers Using jQuery</title>
		<link>http://www.hackification.com/2009/09/02/resizing-single-image-rollovers-using-jquery/</link>
		<comments>http://www.hackification.com/2009/09/02/resizing-single-image-rollovers-using-jquery/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 14:28:00 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[rollovers]]></category>
		<category><![CDATA[sprites]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=252</guid>
		<description><![CDATA[In this article I describe how to create shaped buttons in HTML/CSS that size to their content, have roll-over state, and require only a single image, using jQuery. I&#8217;m sure most web developers know about image rollovers (using separate images for normal and &#8220;hover&#8221; states of anchors). Hopefully also the use of &#8220;CSS Sprites&#8221; is [...]]]></description>
			<content:encoded><![CDATA[<p>In this article I describe how to create shaped buttons in HTML/CSS that size to their content, have roll-over state, and require only a single image, using jQuery.</p>
<p><span id="more-252"></span></p>
<p>I&#8217;m sure most web developers know about image rollovers (using separate images for normal and &#8220;hover&#8221; states of anchors). Hopefully also the use of &#8220;<a href="http://www.alistapart.com/articles/sprites" target="_blank">CSS Sprites</a>&#8221; is becoming better known &#8211; combining the normal and rollover images into a single physical image file to speed up load times and reduce flicker. I won&#8217;t cover those techniques here.</p>
<p>However, if you want the anchor or button to size to its contents, it&#8217;s more difficult to make use of these techniques. Here&#8217;s one way.</p>
<p><img class="aligncenter size-full wp-image-258" title="Sizing Rollovers" src="http://www.hackification.com/wp-content/uploads/2009/09/SizingRollovers.png" alt="Sizing Rollovers" width="414" height="127" /></p>
<p style="text-align: center;"><em>(The final result &#8211; <a href="http://www.hackification.com/jquery-examples/sizing-rollovers/sizing-rollovers.htm" target="_blank">view demo</a>).</em></p>
<p><strong>Start With Markup</strong></p>
<p>Before diving into fancy techniques, get the markup down as you would like it, if you didn&#8217;t have to style anything.</p>
<pre>&lt;a href="..." class="rollover"&gt;Button Text&lt;/a&gt;</pre>
<p>Ideally we want the markup to be clean and not compromised by styling requirements.</p>
<p><strong>Handle Degradation Gracefully</strong></p>
<p>My technique is going to make use of JavaScript, so let&#8217;s handle the case where the user has it disabled for some reason. Here&#8217;s some very basic CSS to give the button a simple style:</p>
<pre>a.rollover
{
  background-color: #00f;
  border: solid 1px #000;
  color: #fff;
  font-weight: bold;
  padding: 4px;
  text-decoration: none;
}

a.rollover:hover
{
  background-color: #008;
}</pre>
<p><strong>Add Styling Naively</strong></p>
<p>Next, I&#8217;m going to add some rollover styling &#8211; but in a way that isn&#8217;t complete. Firstly I created a simple rollover image, but made it very wide &#8211; it needs to be at least as wide as the widest button is ever going to be:</p>
<p><img class="aligncenter size-full wp-image-256" title="Button Rollover" src="http://www.hackification.com/wp-content/uploads/2009/09/buttons.png" alt="Button Rollover" width="657" height="123" /></p>
<p>I&#8217;m going to define my rollover styling against a class selector of &#8220;extra&#8221; &#8211; you&#8217;ll see where that comes from in a moment.</p>
<pre>a.rollover.extra
{
  background: url(buttons.png) repeat-x left 0;
  border: none;
  height: 27px;
  padding: 23px 40px 10px 40px;
  position: relative;
}

a.rollover.extra:hover
{
  background-position: left -57px;
}</pre>
<p>Note that we&#8217;ve had to undo some of the styles applied previously, such as border.</p>
<p>We&#8217;re kind of getting there, but our buttons won&#8217;t look correct on the right-hand-side.</p>
<p><strong>Use JavaScript To Add Styling Markup</strong></p>
<p>To fix the right-hand end-caps, we need to modify our markup. However, I really don&#8217;t want to have to do that on my pages &#8211; afterall, I might change my mind about the site styling.</p>
<p>Here I recommend using JavaScript to tweak at runtime the markup to what we need. I&#8217;m going to use jQuery for this:</p>
<pre>$(function() {
  $('.rollover')
    .addClass('extra')
    .append('&lt;div class="cap"&gt;&lt;/div&gt;');
});</pre>
<p>Basically, when the pad is ready, I find all elements with class &#8220;rollover&#8221;, add another class (&#8220;extra&#8221;), and append into the rollover button an empty span element which has a class of &#8220;cap&#8221;.</p>
<p>That class &#8220;extra&#8221; triggers the image rollovers. The &#8220;cap&#8221; span can be styled as follows:</p>
<pre>a.rollover.extra .cap
{
  background: url(buttons.png) no-repeat right 0;
  height: 100%;
  position: absolute;
  right: 0;
  top: 0;
  width: 40px;
}

a.rollover.extra:hover .cap
{
  background-position: right -57px;
}</pre>
<p>And voila!</p>
<blockquote><p><a href="http://www.hackification.com/jquery-examples/sizing-rollovers/sizing-rollovers.htm" target="_blank">If you&#8217;d like to see this technique in action, please view the demo</a>.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/09/02/resizing-single-image-rollovers-using-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HOWTO: Fix Windows Explorer After Installing Internet Explorer 8</title>
		<link>http://www.hackification.com/2009/07/10/howto-fix-windows-explorer-after-installing-internet-explorer-8/</link>
		<comments>http://www.hackification.com/2009/07/10/howto-fix-windows-explorer-after-installing-internet-explorer-8/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 17:53:43 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ie8]]></category>
		<category><![CDATA[internet explorer 8]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=236</guid>
		<description><![CDATA[I wrote an article about this problem a while back &#8211; but it seems that the fix is relevant to more than just 64-bit installs of Vista, so I thought I&#8217;d re-release it in the hope that it reaches and helps a few more people. Unfortunately, it seems that installing Internet Explorer 8 (IE8) sometimes [...]]]></description>
			<content:encoded><![CDATA[<p><em>I wrote an <a href="http://www.hackification.com/2009/04/01/howto-repair-your-vista-64-bit-system-after-internet-explorer-8/" target="_blank">article</a> about this problem a while back &#8211; but it seems that the fix is relevant to more than just 64-bit installs of Vista, so I thought I&#8217;d re-release it in the hope that it reaches and helps a few more people.</em></p>
<p><span id="more-236"></span></p>
<p>Unfortunately, it seems that installing Internet Explorer 8 (IE8) sometimes has some adverse affects on other applications. Here’s how to fix this.</p>
<p>The problems we’ve experienced following installation of IE8 have been:</p>
<ul>
<li>Windows Explorer opens folders in new windows, even if you have “Open each window in the same folder” checked;</li>
<li>“Open in new tab” doesn’t work in IE8;</li>
<li>Can’t connect to databases using SQL Management Studio Express 2008 (”Unable to cast COM object of type ‘System.__ComObject’ to interface type ‘Microsoft.VisualStudio.OLE.Interop.IServiceProvider’. Exception from HRESULT: 0×80004002 (E_NOINTERFACE)”).</li>
</ul>
<p>The solution is pretty simple:</p>
<ol>
<li>Go to Start -&gt; All Programs -&gt; Accessories, right-click “Command Prompt”, and choose “Run as Administrator”.</li>
<li>OK the user access warning dialogs.</li>
<li>Enter “regsvr32 actxprxy.dll”.</li>
<li>Reboot.</li>
</ol>
<p>Simples! No more tearing my hair out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/07/10/howto-fix-windows-explorer-after-installing-internet-explorer-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Forcing The Browser To Cache Dynamic Content In ASP.NET</title>
		<link>http://www.hackification.com/2009/05/01/forcing-the-browser-to-cache-dynamic-content-in-aspnet/</link>
		<comments>http://www.hackification.com/2009/05/01/forcing-the-browser-to-cache-dynamic-content-in-aspnet/#comments</comments>
		<pubDate>Fri, 01 May 2009 09:14:41 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[caching]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=143</guid>
		<description><![CDATA[Usually, you don&#8217;t want the browser doing any kind of caching on dynamic content served from a generic handler (.ASHX) in ASP.NET &#8211; afterall, the content is usually changing (dynamic). Sometimes however, it&#8217;s handy to use a handler to serve content that effectively never changes. Here&#8217;s how. One common example (that we make use of [...]]]></description>
			<content:encoded><![CDATA[<p>Usually, you don&#8217;t want the browser doing any kind of caching on dynamic content served from a generic handler (.ASHX) in ASP.NET &#8211; afterall, the content is usually changing (dynamic). Sometimes however, it&#8217;s handy to use a handler to serve content that effectively never changes. Here&#8217;s how.</p>
<p><span id="more-143"></span>One common example (that we make use of heavily in <a title="EasyAs123Web.com" href="http://www.easyas123web.com" target="_blank">EasyAs123Web.com</a>) is using a handler to serve and generate images on-the-fly. Our user images are stored in the database, and are immutable &#8211; they never change. Hence we&#8217;d like the client browser to cache the image returned.</p>
<p><strong>Example Handler</strong></p>
<p>Let&#8217;s start with the shell of a generic handler, MyHandler.ashx.cs:</p>
<pre>public class MyHandler : IHttpHandler
{
  public void ProcessRequest( HttpContext context )
  {
    ...
  }

  public bool IsReusable
  {
    get
    {
      return true;
    }
  }
}</pre>
<p>Further code will go where I&#8217;ve marked with ellipses.</p>
<p><strong>Reponse Headers</strong></p>
<p>For some reason, ASP.NET automatically adds headers that stop the browser from caching the content, and you can&#8217;t just override them. Instead, you&#8217;ll need to clear them all out first:</p>
<pre>context.Response.ClearHeaders();</pre>
<p>Next we want to mark the content as fully cacheable, and expiring at some date in the future:</p>
<pre>context.Response.Cache.SetValidUntilExpires( true );
context.Response.Cache.SetCacheability( HttpCacheability.Public );
context.Response.Cache.SetExpires( DateTime.Now.AddMonths( 1 ) );
context.Response.Cache.SetLastModified( DateTime.Now.AddMonths( -1 ) );</pre>
<p>(I&#8217;ve marked the content as expiring in a month, but you could easily add a year or ten years or whatever).</p>
<p>If you are able to calculate some form of hash for your content (which you should be able to do pretty easily), you can add an <a href="http://en.wikipedia.org/wiki/HTTP_ETag" target="_blank">ETag</a>:</p>
<pre>Guid hash = ...;

context.Response.Cache.SetETag( "\"" + hash.ToString().Replace( "-", "" ) + "\"" );</pre>
<p>Finally, there&#8217;s one more trick which is incredibly useful for allowing browsers to avoid re-downloading the content.</p>
<p>Browsers may include the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25" target="_blank">&#8220;If-Modified-Since&#8221; request header</a>. If you ignore this header, no problems occur: you just send the content as usual. However, you can use it to inform the browser that your content hasn&#8217;t changed since the last time it was requested.</p>
<p>If your content really hasn&#8217;t changed, instead of sending a &#8220;200 OK&#8221; response with all the content, you can send back a &#8220;304 Not Modified&#8221; without any content whatsoever:</p>
<pre>var textIfModifiedSince = context.Request.Headers["If-Modified-Since"];

if( !string.IsNullOrEmpty( textIfModifiedSince ) )
{
  context.Response.Status = "304 Not Modified";
  context.Response.End();

  return;
}</pre>
<p>So instead of sending back a potentially large piece of content, you can send back just the tiny response headers.</p>
<p>You can do a similar trick with <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26" target="_blank">&#8220;If-None-Match&#8221;</a> &#8211; I&#8217;ll leave that as an exercise.</p>
<p><strong>Debugging</strong></p>
<p>Making these changes is all very well, but can you be sure that your changes are actually having the desired effects?</p>
<p>There are two great tools you can use to actually view the requests sent by the browser, and the response sent from your web-app:</p>
<ul>
<li>For debugging with Firefox: <a href="https://addons.mozilla.org/en-US/firefox/addon/3829" target="_blank">Live HTTP Headers</a>.</li>
<li>For Internet Explorer: <a href="http://www.fiddler2.com/fiddler2/" target="_blank">Fiddler 2</a>.</li>
</ul>
<p>If you care about the speed and bandwidth usage of your ASP.NET application, I&#8217;d say that these two are pretty much indispensable. You&#8217;ll want to test with both: different browsers make subtly different requests, and interpret the responses differently.</p>
<p>You might also want to use <a href="https://addons.mozilla.org/en-US/firefox/addon/5369" target="_blank">YSlow</a> for Firebug: this has some nice graphical displays of page assets.</p>
<p><strong>Example &#8211; Content Not In Cache</strong></p>
<p>Request and response, some lines omitted for clarity.<strong><br />
</strong></p>
<pre>GET /!!/_Serving/StaticFile/Style/Pro/Images/HomeCreate.jpg HTTP/1.1
Host: www.easyas123web.com</pre>
<pre>HTTP/1.x 200 OK
Cache-Control: public
Content-Type: image/jpeg
Expires: Mon, 01 Jun 2009 08:58:36 GMT
Last-Modified: Wed, 01 Apr 2009 08:58:36 GMT
Etag: "45403f772717d1c63c0b8774e4a124b7"
Content-Length: 20696
... 20K of content here ...</pre>
<p><strong>Example &#8211; Content In Cache</strong></p>
<p>Request and response, some lines omitted for clarity.<strong><br />
</strong></p>
<pre>GET /!!/_Serving/StaticFile/Style/Pro/Images/HomeCreate.jpg HTTP/1.1
Host: www.easyas123web.com
If-Modified-Since: Wed, 01 Apr 2009 08:58:36 GMT</pre>
<pre>HTTP/1.x 304 Not Modified
Cache-Control: public
Expires: Mon, 01 Jun 2009 09:03:51 GMT
Last-Modified: Wed, 01 Apr 2009 09:03:51 GMT
Etag: "45403f772717d1c63c0b8774e4a124b7"</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/05/01/forcing-the-browser-to-cache-dynamic-content-in-aspnet/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using WPF To Generate Web Images</title>
		<link>http://www.hackification.com/2009/04/10/using-wpf-to-generate-web-images/</link>
		<comments>http://www.hackification.com/2009/04/10/using-wpf-to-generate-web-images/#comments</comments>
		<pubDate>Fri, 10 Apr 2009 21:27:37 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[wpf]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=95</guid>
		<description><![CDATA[Recently I needed to display rotated graphics within a web-page. Since there&#8217;s no way to do that cross-browser using CSS, I needed to auto-generate a collection of pre-rotated images that could be displayed as CSS sprites. I&#8217;ve found that WPF (Windows Presentation Foundation) is great for generating batches of images suitable for use in web [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I needed to display rotated graphics within a web-page. Since there&#8217;s no way to do that cross-browser using CSS, I needed to auto-generate a collection of pre-rotated images that could be displayed as CSS sprites. I&#8217;ve found that WPF (Windows Presentation Foundation) is great for generating batches of images suitable for use in web apps.</p>
<p><span id="more-95"></span></p>
<p>Let&#8217;s start with an example graphic, Arrow.xaml:</p>
<pre>&lt;UserControl x:Class="WebImagesGenerator.Graphics.Arrow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Height="64" Width="64"&gt;
  &lt;Canvas Width="64" Height="64"&gt;
    &lt;Polygon Points="32,4 60,32 42,32 42,60 22,60 22,32 4,32"
      Fill="Red" Stroke="Black"
      StrokeThickness="3" StrokeLineJoin="Round" /&gt;
  &lt;/Canvas&gt;
&lt;/UserControl&gt;</pre>
<p>That&#8217;s just a standard XAML file, nothing fancy there.</p>
<p>Rendering WPF content to an image is really easy; you use the RenderTargetBitmap class. I wanted to be able to produce a strip of images, all the same except rotated, that can be used as CSS sprites. For my actual web application, I have a quick console application that generates the images as a batch. If I ever change the XAML files, I can quickly re-generate all the auto-generated images in my project just be running my console application.</p>
<p>Let&#8217;s get started on the console application:</p>
<pre>[STAThread]
static void Main( string[] args )
{
  var arrow = new Graphics.Arrow();

  SaveStrip( arrow, GenerateSeries( 0, 360, 10 )
           , "..\\..\\Testing\\arrows.png" );
}</pre>
<p>WPF must be run in a [STAThread] context. I create an instance of my graphic, then call my SaveStrip routine. GenerateSeries simply returns an array of integers:</p>
<pre>static int[] GenerateSeries( int start, int end, int step )
{
  var series = new List&lt;int&gt;();

  for( var v = start; v &lt; end; v += step )
  {
    series.Add( v );
  }

  return series.ToArray();
}</pre>
<p>The real magic happens in SaveStrip:</p>
<pre>static void SaveStrip( FrameworkElement fe, int[] angles, string filename )
{
  var outer = new Canvas();

  outer.Width = fe.Width * angles.Length;
  outer.Height = fe.Height;

  outer.Children.Add( fe );

  outer.Arrange( new Rect( 0, 0, outer.Width, outer.Height ) );

  var bmp = new RenderTargetBitmap
    ( (int) fe.Width * angles.Length
    , (int) fe.Height, 96, 96, PixelFormats.Pbgra32 );

  for( var i = 0; i &lt; angles.Length; ++i )
  {
    var transforms = new TransformGroup();

    transforms.Children.Add
      ( new RotateTransform( angles[i], fe.Width / 2, fe.Height / 2 ) );

    fe.RenderTransform = transforms;
    fe.SetValue( Canvas.LeftProperty, i * fe.Width );

    // The following line is VITAL!
    outer.Arrange( new Rect( 0, 0, outer.Width, outer.Height ) );

    bmp.Render( fe );
  }

  var encoder = new PngBitmapEncoder();

  encoder.Frames.Add( BitmapFrame.Create( bmp ) );

  using( var stream = File.Create( filename ) )
  {
    encoder.Save( stream );
  }
}</pre>
<p>When I first tried this technique, all my output bitmaps were completely blank. After debugging for a while, I realised that all my graphics were of zero size. You MUST call Arrange() on your elements before calling Render(), otherwise they won&#8217;t have been laid out properly.</p>
<p>When run, this console app produces the following (reduced in size to fit):</p>
<p><img class="alignnone size-full wp-image-102" title="WPF-Generated Images" src="http://www.hackification.com/wp-content/uploads/2009/04/arrows1.png" alt="WPF-Generated Images" width="580" height="15" /></p>
<p>Fantastic! To get a better idea of how such images might appear in a web-page, I&#8217;ve created a little HTML+jQuery demo to see a very quick example of the images in use:</p>
<blockquote><p><strong><a href="http://www.hackification.com/jquery-examples/test-wpf-images.htm" target="_blank">View Demo</a></strong></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/04/10/using-wpf-to-generate-web-images/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>HOWTO: Repair Your Vista 64-bit System After Internet Explorer 8</title>
		<link>http://www.hackification.com/2009/04/01/howto-repair-your-vista-64-bit-system-after-internet-explorer-8/</link>
		<comments>http://www.hackification.com/2009/04/01/howto-repair-your-vista-64-bit-system-after-internet-explorer-8/#comments</comments>
		<pubDate>Wed, 01 Apr 2009 18:28:47 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[EasyAs123Web.com]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ie8]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=86</guid>
		<description><![CDATA[Internet Explorer 8 (IE8) has now been released to the public, and while it&#8217;s not enough to shift me from Firefox, I&#8217;m happy that it offers standards-compliant rendering and a useful &#8220;compatibility view&#8221;, meaning that web developers can essentially test on IE7 and IE8 without needing virtual machines. Unfortunately, when installed on 64-bit Vista (x64), [...]]]></description>
			<content:encoded><![CDATA[<p>Internet Explorer 8 (IE8) has now been released to the public, and while it&#8217;s not enough to shift me from Firefox, I&#8217;m happy that it offers standards-compliant rendering and a useful &#8220;compatibility view&#8221;, meaning that web developers can essentially test on IE7 and IE8 without needing virtual machines. Unfortunately, when installed on 64-bit Vista (x64), it seems to have some adverse affects on other applications. Here&#8217;s how to fix this.</p>
<p><span id="more-86"></span></p>
<p>The problems we&#8217;ve experienced following installation of IE8 have been:</p>
<ul>
<li>Windows Explorer opens folders in new windows, even if you have &#8220;Open each window in the same folder&#8221; checked;</li>
<li>&#8220;Open in new tab&#8221; doesn&#8217;t work in IE8;</li>
<li>Can&#8217;t connect to databases using SQL Management Studio Express 2008 (&#8220;Unable to cast COM object of type &#8216;System.__ComObject&#8217; to interface type &#8216;Microsoft.VisualStudio.OLE.Interop.IServiceProvider&#8217;. Exception from HRESULT: 0&#215;80004002 (E_NOINTERFACE)&#8221;).</li>
</ul>
<p>The solution is pretty simple:</p>
<ol>
<li>Go to Start -&gt; All Programs -&gt; Accessories, right-click &#8220;Command Prompt&#8221;, and choose &#8220;Run as Administrator&#8221;.</li>
<li>OK the user access warning dialogs.</li>
<li>Enter &#8220;regsvr32 actxprxy.dll&#8221;.</li>
<li>Reboot.</li>
</ol>
<p>Sorted! No more tearing my hair out.<a href="http://msmvps.com/blogs/martinpoon/archive/2009/03.aspx" target="_blank"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/04/01/howto-repair-your-vista-64-bit-system-after-internet-explorer-8/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Controlling Browser Content Expiration in ASP.NET</title>
		<link>http://www.hackification.com/2009/01/29/controlling-browser-content-expiration-in-aspnet/</link>
		<comments>http://www.hackification.com/2009/01/29/controlling-browser-content-expiration-in-aspnet/#comments</comments>
		<pubDate>Thu, 29 Jan 2009 16:27:10 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[expiration]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=73</guid>
		<description><![CDATA[Correctly controlling content expiration is a tricky thing. You need to balance two goals: getting the browser to cache as much as possible to reduce page load times and bandwidth, versus not showing the user stale content. In this article I&#8217;ll cover a simple technique (with code) to solve this issue in ASP.NET for stylesheets [...]]]></description>
			<content:encoded><![CDATA[<p>Correctly controlling content expiration is a tricky thing. You need to balance two goals: getting the browser to cache as much as possible to reduce page load times and bandwidth, versus not showing the user stale content. In this article I&#8217;ll cover a simple technique (with code) to solve this issue in ASP.NET for stylesheets and scripts.</p>
<p><span id="more-73"></span></p>
<p>Simplifying things a little, every file you serve to a browser comes with an expiration date. This can be an immediate expiration (as you&#8217;d set for dynamic pages), or sometime in the future. Generally, if the browser needs a particular file again, and it hasn&#8217;t expired, it will try to use a cached copy, and not ask your server for it again.</p>
<p>Let&#8217;s consider stylesheets and scripts.</p>
<ul>
<li>They are required on every page view;</li>
<li>They don&#8217;t change often;</li>
<li>But when they do change (eg a bug fix), you want your users to see the changes.</li>
</ul>
<p>With standard content expiration, we have three choices:</p>
<ul>
<li>They could expire immediately &#8211; however this would mean they would be re-requested every page view;</li>
<li>They could expire after a a set length of time (say a day) &#8211; this is a compromise, meaning they would only be re-requested at most every day, but bug fixes would take a day to appear;</li>
<li>They could never expire &#8211; the user would have to explicitly refresh the page to get any changes.</li>
</ul>
<p>None of these options are ideal, but there is a better way.</p>
<p><strong>Content Should Expire Only When It Changes</strong></p>
<p>If we had the time, we could version every file. We&#8217;d start with &#8216;stylesheet-1.css&#8217;, and when it changed, rename it to &#8216;stylesheet-2.css&#8217;, and fix up every single reference in the website to the new name. If the content expiration for these versioned files was set to &#8216;never&#8217; (or a long time in the future), we would have solved the problem.</p>
<p>Doing that by hand would be a real pain &#8211; hence we need an automated way. An alternative to integer versioning is a hash &#8211; whenever the content changes, the hash will too &#8211; and to save the trouble of renaming files, we can easily add the hash as a query string. Of course, you&#8217;ll need to make sure that the content expiry of these hashed files is marked as &#8216;never&#8217; &#8211; either via IIS, or via some form of static-file handler.</p>
<p>The following code shows how to automatically add these hashes. The pattern I&#8217;m going to use is a UserControl, into which we place script or stylesheet references, for example:</p>
<pre>&lt;%@ Register TagPrefix="co" TagName="CacheControl" Src="~/.../CacheControl.ascx" %&gt;

&lt;co:CacheControl runat="server"&gt;
  &lt;link rel="Stylesheet" href="Path/To/Reset.css" /&gt;
  &lt;link rel="Stylesheet" href="Path/To/Base.css" /&gt;
&lt;/co:CacheControl&gt;</pre>
<p>The output will be something like:</p>
<pre>&lt;link rel="Stylesheet" href="Path/To/Reset.css?hash=567164ca-96c5-6305-a697-a12be0f98499" /&gt;
&lt;link rel="Stylesheet" href="Path/To/Base.css?hash=6a11adca-1593-a529-a574-735cb308a9a7" /&gt;</pre>
<p><strong>Source Code</strong></p>
<p>To support this pattern of usage, we&#8217;ll need to add a couple of attributes:</p>
<pre>[ParseChildren( false )]
[PersistChildren( true )]
public partial class CacheControl : System.Web.UI.UserControl
{
  ...
}</pre>
<p>Now on to the main code. Basically, the UserControl needs to get the concatenated text of the controls inside itself, transform that text (adding the hashes), then replace its own content:</p>
<pre>protected void Page_Load( object sender, EventArgs e )
{
  var content = string.Empty;

  foreach( Control control in Controls )
  {
    var literal = control as LiteralControl;
    var generic = control as HtmlGenericControl;

    if( literal != null )
    {
      content += literal.Text;
    }
    else if( generic != null )
    {
      var text = "&lt;" + generic.TagName + " ";

      foreach( string key in generic.Attributes.Keys )
      {
        text += key + "=\"" + generic.Attributes[key] + "\" ";
      }

      text += "/&gt;";

      content += text;
    }
    else
    {
      throw new InvalidOperationException();
    }
  }

  content = content.Trim();

  Controls.Clear();

  lock( _lock )
  {
    string output;

    if( !_mapInputToOutput.TryGetValue( content, out output ) )
    {
      output = ApplyCacheControl( Context, content );

#if !DEBUG
      _mapInputToOutput.Add( content, output );
#endif
    }

    Controls.Add( new LiteralControl
    {
      Text = output
    } );
  }
}
private static object _lock = new object();
private static Dictionary&lt;string, string&gt; _mapInputToOutput = new Dictionary&lt;string, string&gt;();</pre>
<p>(Since the same conversions will be applied over and over, I&#8217;m storing the results. I&#8217;m also assuming that whenever the file content changes, the web server will be re-started).</p>
<p>The next part parses the content as XML, iterates over the sub-items, determines which attribute contains the path, and writes back the transformed filename:</p>
<pre>private string ApplyCacheControl( HttpContext context, string input )
{
  var xdoc = XDocument.Parse( "&lt;root&gt;" + input + "&lt;/root&gt;" );
  var sb = new StringBuilder();

  sb.Append( Environment.NewLine );

  foreach( var child in xdoc.Root.Elements() )
  {
    var linkAttrName = GetLinkAttribute( child );
    var sourceFile = child.Attribute( linkAttrName ).Value;

    var hash = GetFileHash( sourceFile );

    child.Attribute( linkAttrName ).Value = TransformFilename( context, sourceFile, hash );

    var childText = child.ToString();

    if( childText.StartsWith( "&lt;script" ) &amp;&amp; childText.EndsWith( "/&gt;" ) )
    {
      childText = childText.Substring( 0, childText.Length - 2 ).Trim() + "&gt;&lt;/script&gt;";
    }

    sb.Append( childText );
    sb.Append( Environment.NewLine );
  }

  return sb.ToString();
}

private static string GetLinkAttribute( XElement element )
{
  switch( element.Name.LocalName )
  {
    case "link":
      return "href";
    case "script":
      return "src";
    default:
      throw new InvalidOperationException();
  }
}</pre>
<p>Calculating the hash of the file is pretty easy:</p>
<pre>private Guid GetFileHash( string filename )
{
  var baseUri = Code.Site.Path.GetBaseUri( Request );

  if( filename.StartsWith( baseUri.AbsoluteUri ) )
  {
    filename = filename.Substring( baseUri.AbsoluteUri.Length );
  }

  filename = filename.Replace( '/', '\\' );

  var localPath = Path.Combine( Request.PhysicalApplicationPath, filename );
  Guid hash;

  if( !_mapFileToHash.TryGetValue( localPath, out hash ) )
  {
    var ms = new MemoryStream();

    using( var fs = new FileStream( localPath, FileMode.Open, FileAccess.Read, FileShare.Read ) )
    {
      Utility.StreamCopy( fs, ms );
    }

    var myMD5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
    var hashedTextInBytes = myMD5.ComputeHash( ms.ToArray() );

    hash = new Guid( hashedTextInBytes );

#if !DEBUG
    _mapFileToHash.Add( localPath, hash );
#endif
  }

  return hash;
}
private static Dictionary&lt;string, Guid&gt; _mapFileToHash = new Dictionary&lt;string, Guid&gt;();</pre>
<p>(Again, cached for speed).</p>
<p>Here&#8217;s my utility stream copy routine:</p>
<pre>public static class Utility
{
  public static void StreamCopy( Stream from, Stream to )
  {
    if( from == to )
    {
      return;
    }

    var buffer = new byte[4096];

    from.Seek( 0, SeekOrigin.Begin );

    while( true )
    {
      var done = from.Read( buffer, 0, 4096 );

      if( done &lt;= 0 )
      {
        return;
      }

      to.Write( buffer, 0, done );
    }
  }
}</pre>
<p>Finally, the function to transform the filename:</p>
<pre>private string TransformFilename( HttpContext context, string filename, Guid hash )
{
  filename += "?hash=" + hash.ToString();

  return filename;
}</pre>
<p>You might be wondering why I passed the HttpContext all the way through to this function, only to not use it. Well in my code I do use it &#8211; I further transform the filename to pass it onto a handler for static files, that sets the expiry to &#8216;never&#8217;.</p>
<p>[Updated 01 Feb 2009 - I've added the debug conditionals to make debugging a little easier - now in debug you can change your scripts and stylesheets on the fly and the browser will get the latest version.]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/01/29/controlling-browser-content-expiration-in-aspnet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How-To: Delete a cookie in ASP.NET</title>
		<link>http://www.hackification.com/2009/01/25/how-to-delete-a-cookie-in-aspnet/</link>
		<comments>http://www.hackification.com/2009/01/25/how-to-delete-a-cookie-in-aspnet/#comments</comments>
		<pubDate>Sun, 25 Jan 2009 13:35:35 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[cookies]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=70</guid>
		<description><![CDATA[Deleting a cookie from ASP.NET is something that trips up a lot of people (myself included when I first started ASP.NET coding). Here&#8217;s how: What confused me originally is that HttpCookieCollection contains a Remove method. This doesn&#8217;t remove cookies from the user&#8217;s browser. It only removes the cookie entry from the local collection. What you [...]]]></description>
			<content:encoded><![CDATA[<p>Deleting a cookie from ASP.NET is something that trips up a lot of people (myself included when I first started ASP.NET coding). Here&#8217;s how:</p>
<p><span id="more-70"></span></p>
<p>What confused me originally is that HttpCookieCollection contains a Remove method. <em>This doesn&#8217;t remove cookies from the user&#8217;s browser</em>. It only removes the cookie entry from the local collection. What you have to do is force the user&#8217;s browser to delete the cookie itself. The way to do this is to add an expired cookie: the browser will then clean up the cookie itself.</p>
<pre>void DeleteCookie( HttpContext context, string name )
{
  var cookie = context.Request.Cookies[name];

  if( cookie != null )
  {
    cookie.Expires = DateTime.Now.AddYears( -30 );

    context.Response.Cookies.Add( cookie );
  }
}</pre>
<p>Note that I&#8217;m looking up the cookie in the request, but adding the expired cookie in the response.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2009/01/25/how-to-delete-a-cookie-in-aspnet/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Developing a jQuery Plug-In: Virtual Earth Maps</title>
		<link>http://www.hackification.com/2008/12/18/developing-a-jquery-plug-in-virtual-earth-maps/</link>
		<comments>http://www.hackification.com/2008/12/18/developing-a-jquery-plug-in-virtual-earth-maps/#comments</comments>
		<pubDate>Thu, 18 Dec 2008 14:42:48 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[virtual earth]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=63</guid>
		<description><![CDATA[One of the really nice features of the jQuery JavaScript library is that it allows you to very easily write plug-in methods for it. Custom jQuery plug-ins are called by the end-user in exactly the same way as the core jQuery methods, and make use of the powerful querying syntax. On top of all that, [...]]]></description>
			<content:encoded><![CDATA[<p>One of the really nice features of the jQuery JavaScript library is that it allows you to very easily write plug-in methods for it. Custom jQuery plug-ins are called by the end-user in exactly the same way as the core jQuery methods, and make use of the powerful querying syntax. On top of all that, they&#8217;re really easy to write! In this article, I&#8217;ll explain how to write a jQuery plug-in that displays postal addresses as Virtual Earth maps.</p>
<p><span id="more-63"></span></p>
<blockquote><p><a href="http://www.hackification.com/jquery-examples/virtual-earth-inline.htm" target="_blank">Click here for a demo of the code in this example.</a></p></blockquote>
<p><strong>Imagine There&#8217;s No JavaScript</strong></p>
<p>The first thing you need to do before writing a plug-in is to consider what pattern of HTML elements you&#8217;re trying to re-present to the user. One useful starting point is to imagine how you&#8217;d present the information if there was no such thing as JavaScript. Since I want to present an address, my semantic HTML will look something like this:</p>
<pre>&lt;div class="address"&gt;
  2 Bradford Close, Exmouth, EX8 5PF
&lt;/div&gt;</pre>
<p>That is, in the absense of JavaScript, my page will still make some sort of sense. Another way of thinking about this is that my page will gracefully degrade if the user doesn&#8217;t have JavaScript enabled (or, for instance, if Google crawls my site).</p>
<p><strong>jQuery Plug-In Architecture</strong></p>
<p>To create a plug-in method that jQuery can make use of, simply add it to the &#8216;fn&#8217; property of jQuery:</p>
<pre>jQuery.fn.createInlineVirtualEarthMap = function() { ... }</pre>
<p>Remember that jQuery allows us to operate on sets of elements. When developing a plug-in, these elements are available via the &#8216;this&#8217; keyword. Since we usually want to operate on all of the elements, a plug-in function usually has the form:</p>
<pre>jQuery.fn.createInlineVirtualEarthMap = function() {
  return this.each(function() { ... });
}</pre>
<p>(The value of the &#8216;each&#8217; function call is returned to permit chaining).</p>
<p><strong>Virtual Earth API</strong></p>
<p><strong>Note:</strong> I&#8217;ve used the Virtual Earth API here instead of Google Maps because of ease-of-use issues: although I think Google Maps is the better product (and easier API), Google has unfortuntely decided that to use their API you must either apply for a key (locked to one domain), or include some obfuscated characters (locked to one address). Since this code is based on that of <a href="http://www.easyas123web.com/" target="_blank">EasyAs123Web.com</a>, which allows users to create their own domains, I&#8217;ve been forced to use Virtual Earth.</p>
<p>Before using the Virtual Earth API, you must obviously include the appropriate script:</p>
<pre>&lt;script charset="UTF-8" type="text/javascript"
  src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&amp;mkt=en-gb"&gt;&lt;/script&gt;</pre>
<p>With that in place, you can then create a map in an element using code such as this:</p>
<pre>var map = new VEMap('id-of-map-div');
map.LoadMap();
map.HideDashboard();
map.Find(null, 'street address', null, null, 0, 1, true, true, true, true,
  function() { map.SetZoomLevel(16); });</pre>
<p>(I&#8217;ve picked a few appropriate values to simply select the first found address. I&#8217;m using a callback on the &#8216;Find&#8217; method to set the zoom level to a hardcoded value).</p>
<p><strong>Generating IDs</strong></p>
<p>As you can see, the Virtual Earth API expects to be passed the ID of the control to create a map in. But what if the element doesn&#8217;t have an ID, as in my example?</p>
<p>There&#8217;s a useful function you can add to jQuery for cases like this:</p>
<pre>if (!jQuery.generateId) {
  jQuery.generateId = function() {
    return arguments.callee.prefix + arguments.callee.count++;
  };
  jQuery.generateId.prefix = 'jq$';
  jQuery.generateId.count = 0;

  jQuery.fn.generateId = function() {
    return this.each(function() {
      this.id = $.generateId();
    });
  };
}</pre>
<p>Note that the function can either be called as a &#8216;static&#8217; method:</p>
<pre>var id = $.generateId();</pre>
<p>Or as a query method:</p>
<pre>$('.whatever').generateId();</pre>
<p>(And also note that it&#8217;s added to jQuery as a plug-in method, exactly as described earlier).</p>
<p><strong>The Final Plug-In</strong></p>
<p>So now we have everything necessary to create our plug-in:</p>
<pre>jQuery.fn.createInlineVirtualEarthMap = function() {
  return this.each(function() {
    if (!this.id) {
      $(this).generateId();
    }

    var address = $(this).text();
    var map = new VEMap(this.id);

    map.LoadMap();
    map.HideDashboard();
    map.Find(null, address, null, null, 0, 1, true, true, true, true,
      function() { map.SetZoomLevel(16); });
  });</pre>
<p>Of course, if you were creating a plug-in for general use, you&#8217;d probably want to allow the user to pass parameters to control the zoom level and other aspects of the map, but since the purpose of this tutorial is only to demonstrate the basics of creating jQuery plug-ins, I haven&#8217;t bothered.</p>
<p><strong>Client Code</strong></p>
<p>To use this plug-in, it&#8217;s a simple matter to call it from a jQuery selector:</p>
<pre>$('.address').createInlineVirtualEarthMap();</pre>
<p>(In the linked example I&#8217;ve applied a style to the class to assign a width and height to the map, and the above call is made in a document.ready block).</p>
<blockquote><p><a href="http://www.hackification.com/jquery-examples/virtual-earth-inline.htm" target="_blank">Click here for a demo of the code in this example.</a></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2008/12/18/developing-a-jquery-plug-in-virtual-earth-maps/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>A Developer&#039;s Introduction to jQuery</title>
		<link>http://www.hackification.com/2008/11/27/a-developers-introduction-to-jquery/</link>
		<comments>http://www.hackification.com/2008/11/27/a-developers-introduction-to-jquery/#comments</comments>
		<pubDate>Thu, 27 Nov 2008 19:56:26 +0000</pubDate>
		<dc:creator>Stu Smith</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[styling]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://www.hackification.com/?p=55</guid>
		<description><![CDATA[I&#8217;ve only been using jQuery for a couple of months now, but I&#8217;ve been immediately impressed by its power and concise syntax. I thought I&#8217;d present it from my (a developer&#8217;s) perspective. I come from a C# background, so this article will be written from that sort of point of view. I&#8217;ll start with an [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve only been using <a title="jQuery: The Write Less, Do More, JavaScript Library" href="http://jquery.com/" target="_blank">jQuery</a> for a couple of months now, but I&#8217;ve been immediately impressed by its power and concise syntax. I thought I&#8217;d present it from my (a developer&#8217;s) perspective. I come from a C# background, so this article will be written from that sort of point of view.</p>
<p>I&#8217;ll start with an example. Suppose I have a HTML table, and I&#8217;d like to do two things:</p>
<ol>
<li>Make it easier to scan visually by applying alternating row colors;</li>
<li>Make it easier to read by having a hot-tracking highlight bar over the rows.</li>
</ol>
<p><strong>CSS Styling<br />
</strong></p>
<p>Before we jump into the jQuery, we need to define a couple of styles in the stylesheet:</p>
<pre>.alt { background-color: #ddd; }
.hover { background-color: #aaf !important; }</pre>
<p><strong>The jQuery Script</strong></p>
<p>Now that&#8217;s sorted, here&#8217;s the jQuery:</p>
<pre>$(function() {
  $('table tbody tr:odd').addClass('alt');

  $('table tbody tr').hover(function() {
    $(this).addClass('hover');
  }, function() {
    $(this).removeClass('hover');
  });
});</pre>
<p>If you&#8217;d like to see a working example, just <a title="jQuery Table Striping Example" href="http://www.hackification.com/jquery-examples/table-striping.htm" target="_blank"><strong>visit this page</strong></a>, and view source.</p>
<p><strong>Dollars Dollars Dollars</strong></p>
<p>The most noticable aspect of a jQuery script is all the dollar signs. Just as C/C++ allow underscores in function names, JavaScript allows dollar signs in identifiers. And just as a single underscore would be a valid (albeit unusual) function name in C/C++, so a single dollar sign is a valid identifier name in JavaScript.</p>
<p>So the first line that begins &#8216;$(&#8230;&#8217; is calling a function called &#8216;$&#8217;. If this bothers you, you can also call jQuery functions using the jQuery identifier. (In other words, &#8216;jQuery(&#8230;)&#8217; is a synonym for &#8216;$(&#8230;)&#8217;).</p>
<p><strong>Functions in Functions</strong></p>
<p>JavaScript is a very expressive language, and unlike the C family of languages, treats functions as first-class citizens that can be treated just like any other object. The jQuery script above has the following form:</p>
<pre>$(function() {
  ...
});</pre>
<p>Or to put it another way, we are calling the function &#8216;$&#8217;, passing a single argument, which is itself an anonymous function.</p>
<p>In jQuery, this is shorthand for attaching an event to be fired when the DOM is ready. So to recap, the anonymous function body (marked &#8216;&#8230;&#8217; above) will be called when the document is ready.</p>
<p><strong>DOM Querying and Manipulation</strong></p>
<p>So we&#8217;ve now established that the two statements within the anonymous function will be called once, when the document is ready. Let&#8217;s consider the first statement:</p>
<pre>$('table tbody tr:odd').addClass('alt');</pre>
<p>Hopefully this statement is a lot easier to understand than the last section. We call a function (&#8216;$&#8217;, as usual), passing a string as a parameter, which returns some object, on which we call a function, passing a second string. (Strings in JavaScript may be enclosed with either single or double quotes).</p>
<p>jQuery functions (named &#8216;$&#8217;) are queries &#8211; they act on the DOM (or portion of it), and essentially return a set of matching elements. One major selling point of jQuery is that it presents a unified and more powerful version of CSS selectors &#8211; and they work cross-browser &#8211; so you don&#8217;t need to worry whether a particular selector works on Internet Explorer.</p>
<p>In the above statement, we want to select all &#8216;tr&#8217; elements, that are children of &#8216;tbody&#8217;, that are children of &#8216;table&#8217;, and furthermore, only select those which are odd-ordered (i.e., at indexes 1,3,5, etc).</p>
<p>Once we&#8217;ve selected these elements, we can act on them as a whole using the various jQuery functions. In the statement above, the call to &#8216;addClass&#8217; will add the named CSS class (&#8216;alt&#8217;) to all elements returned from the query.</p>
<p>Basically, we wanted to write the following in our stylesheet:</p>
<pre>table tbody tr:odd
{
  background-color: #ddd; // See stylesheet at top of page.
}</pre>
<p>&#8230;but we couldn&#8217;t because &#8216;:odd&#8217; isn&#8217;t a supported CSS selector. (Or at least, isn&#8217;t supported in many major browsers).</p>
<p><strong>DOM Events</strong></p>
<p>Onto the last stretch. The second statement is a multi-liner, but if we omit a few details, hopefully things will be clearer:</p>
<pre>$('table tbody tr').hover(function() { ... }, function() { ... });</pre>
<p>We&#8217;re querying the DOM, as before (for tr&#8217;s in tbody&#8217;s in table&#8217;s), then using the &#8216;hover&#8217; function. The hover function is passed two parameters, both of which are anonymous functions.</p>
<p>The &#8216;hover&#8217; method is one of a set of jQuery functions that allow you to attach events to the DOM. In the case of &#8216;hover&#8217;, the first function passed will be called when the mouse moves over the element, and the second called when the mouse moves out.</p>
<p>(Note that as before, these events will be attached to all elements returned by the query, even though there is only a single function call).</p>
<p>When calling the event handler functions, jQuery assigns the variable &#8216;this&#8217; to the element to which the event applies. Wrapping the element in the &#8216;$&#8217; syntax &#8211; $(this) &#8211; allows all the jQuery functions to be used on that element &#8211; in this case, addClass and removeClass.</p>
<p><strong>Conclusion</strong></p>
<p>This has been a longish article, and of course I&#8217;ve barely scratched the surface of what you can do with jQuery, but I&#8217;ve introduced the most important aspects. jQuery provides a browser-independent view of your document, and provides powerful methods for querying, modifying, and attaching events.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hackification.com/2008/11/27/a-developers-introduction-to-jquery/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
	</channel>
</rss>
