<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Matt Berseth</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/" />
    <link rel="self" type="application/atom+xml" href="http://mattberseth.com/atom.xml" />
   <id>tag:mattberseth.com,2008://1</id>
    <link rel="service.post" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1" title="Matt Berseth" />
    <updated>2008-05-15T23:00:51Z</updated>
    <subtitle>A .Net Developer&apos;s Blog</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2ysb5-20051201</generator>
 
<entry>
    <title>ASP.NET AJAX Progress Bar Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/05/aspnet_ajax_progress_bar_contr.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=121" title="ASP.NET AJAX Progress Bar Control" />
    <id>tag:mattberseth.com,2008://1.121</id>
    
    <published>2008-05-15T23:00:07Z</published>
    <updated>2008-05-15T23:00:51Z</updated>
    
    <summary><![CDATA[If you use AJAX in your web app's, you no doubt have made use of some sort of progress/status indicator that lets the user know that some operation is currently executing.&nbsp; In the app I am currently working on we use an animated gif for this.&nbsp; It works great, but sometimes you might find it nice to have more control over the indicator - i.e. interacting with it via JavaScript and styling it using CSS. So I did a little research and found a nice example of one built using script.aculo.us.&nbsp; The demo page looked great so I downloaded the source to get a feel for how it worked.&nbsp; I liked what I saw so I thought I would create a new AjaxControlToolkit control based on this example.&nbsp; My original goal was just to port it over to ASP.NET, but as I started playing around with it I thought I...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="AjaxControlToolkit" />
            <category term="Asp.Net" />
            <category term="Prototype" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>If you use AJAX in your web app's, you no doubt have made use of some sort of progress/status indicator that lets the user know that some operation is currently executing.&nbsp; In the app I am currently working on we use an animated gif for this.&nbsp; It works great, but sometimes you might find it nice to have more control over the indicator - i.e. interacting with it via JavaScript and styling it using CSS.</p> <p><img height="428" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_2ff32630-9724-4602-b817-f3b67e39dca6.png" width="367">  </p> <p>So I did a little research and <a href="http://www.webappers.com/progressBar/">found a nice example</a> of one built using <a href="http://script.aculo.us/">script.aculo.us</a>.&nbsp; The demo page looked great so I downloaded the source to get a feel for how it worked.&nbsp; I liked what I saw so I thought I would create a new <a href="http://ajax.asp.net/ajaxtoolkit/">AjaxControlToolkit</a> control based on this example.&nbsp; My original goal was just to port it over to ASP.NET, but as I started playing around with it I thought I might make a few changes to it as well.&nbsp; So during the process of porting it, I made the following tweaks</p> <ul> <li>I added a mode that runs the progress bar from 0 to 100 continuously.&nbsp; This mode would be useful for scenarios where you don't know how long an operations would run for (like a typical partial postback)  <li>The original requires different images for progress indicators of different widths.&nbsp; I chose to use a repeating background image instead so I could use a single progress image no matter the width of the control.  <li>I add an <strong>updating</strong> CSS class to the control while the progress bar is running.&nbsp; In my demo page I use this to darken the percentage while the indicator is running.&nbsp; I was also thinking about adding the current percentage to the class as well so you could have a custom style applied depending upon what the current percentage is.&nbsp; Then you could do something like <strong><em>.progress .100 {&nbsp; } </em></strong>to control the styling when the indicator is displaying 100%. <li>I used a skinning approach that is very similar to the Toolkit's Tab control.&nbsp; I went ahead and created a bunch of sample skins (shown above) just to make sure my skinning technique worked alright.</li></ul> <p>Below are some details on how the controls - including how to add one to your page, interacting with it from JavaScript and creating custom skins using CSS.&nbsp; Read on if you are interested and don't forget to check out the <a href="http://mattberseth2.com/progress/" target="_blank">live demo</a> and <a href="http://mattberseth2.com/downloads/progress.zip">download</a>.&nbsp; I built it using .Net 3.5 and Toolkit version 3.5.11119.0, but I think it could be ported back to .Net 2.0 without too many issues.&nbsp; </p> <p><a href="http://mattberseth2.com/progress/" target="_blank">Live Demo (IE6, IE7, FF and Opera)</a> | <a href="http://mattberseth2.com/downloads/progress.zip">Download</a></p> <p><strong></strong>&nbsp;</p> <p><strong><u>Using the Control</u></strong></p> <p>The download contains plenty of examples of how to interact with the control, but here is some sample markup that specifies the progress mode as well as the width ...</p> <div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">&lt;!-- Continuous Mode / 150px wide --&gt;</span> </pre><pre><span class="lnum">   2:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl1"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">Mode</span><span class="kwrd">="Continuous"</span> <span class="attr">Width</span><span class="kwrd">="150px"</span> <span class="kwrd">/&gt;</span></pre><pre><span class="lnum">   3:  </span><span class="rem">&lt;!-- Manual Mode / 70px wide --&gt;</span> </pre><pre><span class="lnum">   4:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl12"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="70px"</span> <span class="kwrd">/&gt;</span> </pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p><strong></strong>&nbsp;</p>
<p>When the control is in Continuous mode, you can start and stop the progress animation by using the <strong><em>play()</em></strong> and <strong><em>stop()</em></strong> JavaScript functions</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">//  start the indicator</span></pre><pre><span class="lnum">   2:  </span>$find(<span class="str">'ProgressControl1'</span>).play();</pre><pre><span class="lnum">   3:  </span>&nbsp;</pre><pre><span class="lnum">   4:  </span><span class="rem">//  stop it</span></pre><pre><span class="lnum">   5:  </span>$find(<span class="str">'ProgressControl1'</span>).stop();</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>And when the control is in Manual mode, you can use the set_percentage to manually change the percentage value.&nbsp; You can either provide an absolute value like in the first example, or a value that is relative to what ever the current value is - like the second example.</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">//  set the percentage to 62</span></pre><pre><span class="lnum">   2:  </span>$find(<span class="str">'ProgressControl1'</span>).set_percentage(62);</pre><pre><span class="lnum">   3:  </span>&nbsp;</pre><pre><span class="lnum">   4:  </span><span class="rem">//  increase the percentage by 15</span></pre><pre><span class="lnum">   5:  </span>$find(<span class="str">'ProgressControl1'</span>).set_percentage(<span class="str">'+15'</span>);</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p><strong><u>HTML Emitted by the Control</u></strong></p>
<p>Below is the markup the control emits.&nbsp; 1 DIV for containing the progress image, 1 DIV for displaying the percentage text, 2 DIV's for applying a border and an outer DIV that wraps it all.</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="ajax__progress"</span> <span class="attr">class</span><span class="kwrd">="ajax__progress"</span> <span class="attr">id</span><span class="kwrd">="ProgressControl1"</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">   2:  </span>    <span class="rem">&lt;!-- outer and inner elements for creating a border --&gt;</span></pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="ajax__progress_outer"</span> <span class="attr">id</span><span class="kwrd">="ProgressControl1_outer"</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">   4:  </span>        <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="ajax__progress_inner"</span> <span class="attr">id</span><span class="kwrd">="ProgressControl1_inner"</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">   5:  </span>            <span class="rem">&lt;!-- The background image for this element displays the indicator --&gt;</span></pre><pre><span class="lnum">   6:  </span>            <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="ajax__progress_indicator"</span> <span class="attr">id</span><span class="kwrd">="ProgressControl1_indicator"</span> <span class="kwrd">/&gt;</span></pre><pre><span class="lnum">   7:  </span>        <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">   8:  </span>    <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">   9:  </span>    <span class="rem">&lt;!-- This element displays the percentage --&gt;</span></pre><pre><span class="lnum">  10:  </span>    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="ajax__progress_info"</span> <span class="attr">id</span><span class="kwrd">="ProgressControl1_info"</span><span class="kwrd">&gt;</span>75%<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre><pre><span class="lnum">  11:  </span><span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p><strong><u>Skinning the Control</u></strong></p>
<p>To skin the control, you need to set the CssClass property of the ProgressControl to the name of the CSS class that defines your custom skin.&nbsp; For the skin portion of the demo page I have defined 6 custom themes.&nbsp; Below is the sample markup for this section ...&nbsp; </p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl4"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="green"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre><span class="lnum">   2:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl5"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="yelllow"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre><span class="lnum">   3:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl6"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="orange"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre><span class="lnum">   4:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl7"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="red"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre><span class="lnum">   5:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl8"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="lightblue"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre><span class="lnum">   6:  </span><span class="kwrd">&lt;</span><span class="html">mb:ProgressControl</span> <span class="attr">ID</span><span class="kwrd">="ProgressControl11"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">CssClass</span><span class="kwrd">="solidblue"</span> <span class="attr">Mode</span><span class="kwrd">="Manual"</span> <span class="attr">Width</span><span class="kwrd">="200px"</span> <span class="kwrd">/&gt;</span>            </pre><pre>&nbsp;</pre><pre>&nbsp;</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>And here are the CSS style rules that apply the styles for these skins</p>
<p><img height="677" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_06848509-f446-4f47-9a5d-15fa9279de4a.png" width="518"> </p>
<p>One of the sample skins I made is roughly based on the XP style progress indicator.&nbsp; To create this custom skin, I first created the background image that I want to use for the indicator (I am using a 6 x 9 image)</p>
<p><img height="335" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_e1eb006a-bc50-4564-8025-e5cf3dfe8e83.png" width="241"> </p>
<p>then I use the .ajax__progress_indicator and .ajax__progress_inner classes to override the default skins height and progress image - Simple!</p>
<p><img height="181" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_e63e1b1f-9b0c-4d9f-b21a-11cd64a3b73d.png" width="356"> </p>
<p>And here is how it looks ...</p>
<p><img height="65" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_73b9ebb4-44a3-47a6-894d-0e54407cc88e.png" width="250"> </p>
<p><strong><u>Screen shots of the Control's Features</u></strong></p>
<p>Here are some static images that show off some of the control;s features ...</p>
<p><strong>Continuous Mode</strong></p>
<p>Progress indicator continuously fills the region from left to right.</p>
<p><img height="123" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_e4c0ad85-a55e-4b28-977a-088e49d555f7.png" width="433"> </p>
<p><strong>Fluid Width</strong></p>
<p>Progress indicator continuously fills the region from left to right.</p>
<p><img height="137" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_5e794961-7ab7-4d3d-9906-7158e0ac64a6.png" width="432"> </p>
<p><strong>Manual Mode - Update Absolute Percentage</strong></p>
<p>Use the JavaScript API to set the percentage an absolute value</p>
<p><img height="175" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_2230f6f9-ce67-4639-ad18-bccc67ce2c09.png" width="432"> </p>
<p><strong>Manual Mode - Update Relative Percentage</strong></p>
<p>Use the JavaScript API to set the percentage to a relative value</p>
<p><img height="174" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_e35117f9-f317-4664-99c5-4bd9e1925388.png" width="430"> </p>
<p><strong>Skins</strong></p>
<p>Use CSS to control the progress indicators look and feel</p>
<p><img height="385" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_8cf208bf-aee8-44ae-9cb9-b6c8ffa91b22.png" width="432"> </p>
<p><strong>AJAX Operations</strong></p>
<p>Example of displaying the indicator for AJAX operations </p>
<p><img height="272" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_b448680f-3bd0-42e0-8f1d-814e699bb8eb.png" width="434"> </p>
<p><strong>Modal Popup</strong></p>
<p>An example using the progress control with the Tookit's ModalPopup control</p>
<p><img height="214" alt="image" src="http://mattberseth.com/WindowsLiveWriter/SkinnableAJAXProgressBar_11A1A/image_4a3d43cd-c0bd-4b9a-878d-3727a2de6f4c.png" width="343"> </p>
<p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Bug Bash: Enabling/Disabling the ASP.NET AJAX Timer using the Control&apos;s Client Side API</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/05/bug_bash_enablingdisabling_the.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=120" title="Bug Bash: Enabling/Disabling the ASP.NET AJAX Timer using the Control's Client Side API" />
    <id>tag:mattberseth.com,2008://1.120</id>
    
    <published>2008-05-08T01:37:17Z</published>
    <updated>2008-05-08T01:37:51Z</updated>
    
    <summary><![CDATA[I know most dev's prefer writing new code over fixing/maintaining the existing stuff.&nbsp; And most days I feel the same way.&nbsp; But every once in a while it is kind of fun signing up for that one lingering defect that no one else can seem to fix.&nbsp; Maybe you know the one - its not reproducible, only occurs in production and brings the system to its knee's?&nbsp; Sound familiar? Well I thought I might try something new and blog about some of the juicy bugs we have found hanging out in our app.&nbsp; This might turn into a blog series or something, or maybe not.&nbsp; Who knows. The Bug The app I am currently working on has a page that uses ASP.NET AJAX's new Timer control to automatically refresh the page every 30 seconds.&nbsp; The page is one of those status pages that lets you monitor the progress of some...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="Bug Bash" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>I know most dev's prefer writing new code over fixing/maintaining the existing stuff.&nbsp; And most days I feel the same way.&nbsp; But every once in a while it is kind of fun signing up for that one lingering defect that no one else can seem to fix.&nbsp; Maybe you know the one - its not reproducible, only occurs in production and brings the system to its knee's?&nbsp; Sound familiar?</p> <p>Well I thought I might try something new and blog about some of the juicy bugs we have found hanging out in our app.&nbsp; This might turn into a blog series or something, or maybe not.&nbsp; Who knows. </p> <p><strong><u>The Bug</u></strong></p> <p>The app I am currently working on has a page that uses ASP.NET AJAX's new <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.timer.aspx">Timer</a> control to automatically refresh the page every 30 seconds.&nbsp; The page is one of those status pages that lets you monitor the progress of some off-line processes.&nbsp; Under normal usage a user would make a request to run some off-line process and then be taken to this page where they can monitor the progress.&nbsp; The markup for the Timer looks something like this ...</p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">asp:Timer</span> <span class="attr">ID</span><span class="kwrd">="timer"</span> <span class="attr">runat</span><span class="kwrd">="server"</span> <span class="attr">Interval</span><span class="kwrd">="30000"</span> <span class="attr">OnTick</span><span class="kwrd">="Timer_Tick"</span> <span class="kwrd">/&gt;</span></pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>When the server side Tick event fires we run a bit of code that gets the latest progress/status of the process and updates the UI.&nbsp; If the process has completed or failed, the Timer is turned off and the page quits automatically refreshing.</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">void</span> Timer_Tick(<span class="kwrd">object</span> sender, EventArgs args)</pre><pre><span class="lnum">   2:  </span>{</pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (IsProcessComplete())</pre><pre><span class="lnum">   4:  </span>    {</pre><pre><span class="lnum">   5:  </span>        <span class="rem">//  the work is done, turn off the timer</span></pre><pre><span class="lnum">   6:  </span>        ((Timer)sender).Enabled = <span class="kwrd">false</span>;</pre><pre><span class="lnum">   7:  </span>    }</pre><pre><span class="lnum">   8:  </span>}</pre></div>
<p>The content on the page is mostly read-only, but there is also a single INPUT element and a button that performs a postback.&nbsp; The problem is that sometimes the timer fires and causes the refresh to occur when the user is entering data into the INPUT box.&nbsp; And of course this can be a little irritating and confusing for the user.&nbsp; </p>
<p>This was the defect that rolled across my desk yesterday.&nbsp; So I took a look at the page, reproduced the problem and starting working out how I was going to fix it.&nbsp;&nbsp;&nbsp; </p>
<p><strong><u>The Fix</u></strong></p>
<p>I figured a sensible fix for this bug would be to disable the Timer when the INPUT's client side <strong><em>focus</em></strong> event fires and then re-enable it when <strong><em>blur</em></strong> fires.&nbsp; I described the solution to a few other dev's and everyone seemed to think it made sense.&nbsp; So I went off and started in on creating the fix.</p>
<p><strong><u>The Implementation</u></strong></p>
<p>I added a pageLoad event handler to my page and attached a bit of JavaScript to my INPUT element's <strong><em>focus</em></strong> and <strong><em>blur</em></strong> events that used the Timer component's client side API to enable and disable the timer.</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">function</span> pageLoad(sender, args){</pre><pre><span class="lnum">   2:  </span>    <span class="rem">//  fetch the timer components</span></pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">var</span> timer = $find(<span class="str">'&lt;%= this.timer.ClientID %&gt;'</span>);</pre><pre><span class="lnum">   4:  </span>    <span class="rem">//  fetch the INPUT element</span></pre><pre><span class="lnum">   5:  </span>    <span class="kwrd">var</span> textbox = $get(<span class="str">'&lt;%= this.textbox.ClientID %&gt;'</span>);</pre><pre><span class="lnum">   6:  </span>    </pre><pre><span class="lnum">   7:  </span>    $addHandler(textbox, <span class="str">'focus'</span>, Function.createDelegate(<span class="kwrd">this</span>, <span class="kwrd">function</span>(){</pre><pre><span class="lnum">   8:  </span>       <span class="rem">//   disable the Timer so we don't refresh the page</span></pre><pre><span class="lnum">   9:  </span>       <span class="rem">//   while the user is entering the data</span></pre><pre><span class="lnum">  10:  </span>       timer.set_enabled(<span class="kwrd">false</span>); </pre><pre><span class="lnum">  11:  </span>    }));</pre><pre><span class="lnum">  12:  </span>    </pre><pre><span class="lnum">  13:  </span>    $addHandler(textbox, <span class="str">'blur'</span>, Function.createDelegate(<span class="kwrd">this</span>, <span class="kwrd">function</span>(){</pre><pre><span class="lnum">  14:  </span>       <span class="rem">//   re-enable the Timer</span></pre><pre><span class="lnum">  15:  </span>       timer.set_enabled(<span class="kwrd">true</span>); </pre><pre><span class="lnum">  16:  </span>    }));                </pre><pre><span class="lnum">  17:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p><strong><u>The Bug in the Fix</u></strong></p>
<p>And holy crap I was surprised when this didn't fix the bug.&nbsp; I have worked with some of the other Timer controls before and unless I have <a href="http://sports.espn.go.com/mlb/news/story?id=3243636">misremembered</a>, they all support this kind of thing - just in case you haven't noticed the .Net framework has no shortage of timer controls ;) </p>
<ul>
<li><a href="http://msdn2.microsoft.com/en-us/library/system.windows.forms.timer.aspx">System.Windows.Forms.Timer</a> 
<li><a href="http://msdn2.microsoft.com/en-us/library/system.timers.timer(VS.71).aspx">System.Timers.Timer</a> 
<li><a href="http://msdn2.microsoft.com/en-us/library/system.threading.timer.aspx">System.Threading.Timer</a>&nbsp;</li></ul>
<p>And I figured calling <em><strong>set_enabled(false) </strong></em>would do exactly what I want - turn off the timer.&nbsp; I spent ~10 minutes or so setting breakpoints and making sure my code wasn't faulty before I took a peek at the client side code for the Timer control.&nbsp; And guess what I found out - the Timer control doesn't check the enabled bit before it postback and raises the server side Tick event.&nbsp; <strong>No wonder my fix wasn't working!</strong></p>
<p><strong><u>The Fix to the Bug in the Fix</u></strong></p>
<p>Is anyone else surprised by this?&nbsp; Well I was.&nbsp; So I nosed around the Timer's behavior a little bit more and to see if there was anything else here I could use.&nbsp; And it turns out there is.&nbsp; After a partial postback completes, the server side portion of the Timer control sends the client side 2 bits of data - a value for the timers interval and a boolean value that is true when the timer should be enabled and false otherwise.&nbsp; The client side timer component passes these 2 data items to it's <strong><em>_update </em></strong>function, which in turn either enables or disables the timer and updates the interval value.&nbsp; Here is the code for this function (I added the comments)</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">function</span> Sys$UI$_Timer$_update(enabled,interval) {</pre><pre><span class="lnum">   2:  </span>    <span class="rem">//  check to see if the timer is already disabled</span></pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">var</span> stopped = !<span class="kwrd">this</span>.get_enabled();</pre><pre><span class="lnum">   4:  </span>    <span class="rem">//  check to see of the interval value has changed</span></pre><pre><span class="lnum">   5:  </span>    <span class="kwrd">var</span> intervalChanged = (<span class="kwrd">this</span>.get_interval() !== interval);</pre><pre><span class="lnum">   6:  </span>    <span class="rem">//  if we are not stopped already and either</span></pre><pre><span class="lnum">   7:  </span>    <span class="rem">//  the interval value has changed or we are now</span></pre><pre><span class="lnum">   8:  </span>    <span class="rem">//  disabling the timer, stop the timer</span></pre><pre><span class="lnum">   9:  </span>    <span class="kwrd">if</span> ((!stopped) &amp;&amp; ((!enabled)||(intervalChanged))){</pre><pre><span class="lnum">  10:  </span>        <span class="kwrd">this</span>._stopTimer();</pre><pre><span class="lnum">  11:  </span>        stopped = <span class="kwrd">true</span>;</pre><pre><span class="lnum">  12:  </span>    } </pre><pre><span class="lnum">  13:  </span>    <span class="rem">//  update the enabled bit and interval</span></pre><pre><span class="lnum">  14:  </span>    <span class="kwrd">this</span>.set_enabled(enabled);</pre><pre><span class="lnum">  15:  </span>    <span class="kwrd">this</span>.set_interval(interval);</pre><pre><span class="lnum">  16:  </span>    <span class="rem">//  if the timer needs to be enabled and it is</span></pre><pre><span class="lnum">  17:  </span>    <span class="rem">//  currently stopped, start the timer</span></pre><pre><span class="lnum">  18:  </span>    <span class="kwrd">if</span> ((<span class="kwrd">this</span>.get_enabled()) &amp;&amp; (stopped)){</pre><pre><span class="lnum">  19:  </span>        <span class="kwrd">this</span>._startTimer();</pre><pre><span class="lnum">  20:  </span>    }</pre><pre><span class="lnum">  21:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>So I decided to update my focus and blur event handlers to call this method to enable/disable the Timer.&nbsp; And guess what - now my page functions exactly how I want it to.&nbsp; But of course there are few things that are untidy about this approach:</p>
<ol>
<li>The Timer's <strong><em>_update</em></strong> function is not meant to be invoked like this.&nbsp; Typically the '_' prefix indicates the member is non-public.&nbsp; I suppose this is a bit like using .Net's reflection to invoke a private method on some framework class - probably not a great idea. 
<li>This implementation now allows me to interact with the Timer's client side behavior, but when the page postsback the new enabled and interval values that were set on the client are not sent back to the server.&nbsp; And when the page reloads either from a full or partial postback these values will go back to what the server thinks they should be - essentially overwriting any of the changes you may have made.</li></ol>
<p>But I can live with both of these items.&nbsp; I am betting against Microsoft changing the <strong><em>_update</em></strong> function (if they do, maybe they will support this scenario) and I don't need the values I set on the client sent back to the server.&nbsp; All I want is to be able to control when the Timer fires, and this approach does it.</p>
<div class="csharpcode">
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">function</span> pageLoad(sender, args){</pre><pre><span class="lnum">   2:  </span>    <span class="rem">//  fetch the timer components</span></pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">var</span> timer = $find(<span class="str">'&lt;%= this.timer.ClientID %&gt;'</span>);</pre><pre><span class="lnum">   4:  </span>    <span class="rem">//  fetch the INPUT element</span></pre><pre><span class="lnum">   5:  </span>    <span class="kwrd">var</span> textbox = $get(<span class="str">'&lt;%= this.textbox.ClientID %&gt;'</span>);</pre><pre><span class="lnum">   6:  </span>    </pre><pre><span class="lnum">   7:  </span>    $addHandler(textbox, <span class="str">'focus'</span>, Function.createDelegate(<span class="kwrd">this</span>, <span class="kwrd">function</span>(){</pre><pre><span class="lnum">   8:  </span>       <span class="rem">//   disable the Timer so we don't refresh the page</span></pre><pre><span class="lnum">   9:  </span>       <span class="rem">//   while the user is entering the data</span></pre><pre><span class="lnum">  10:  </span>       timer._update(<span class="kwrd">false</span>, timer.get_interval()); </pre><pre><span class="lnum">  11:  </span>    }));</pre><pre><span class="lnum">  12:  </span>    </pre><pre><span class="lnum">  13:  </span>    $addHandler(textbox, <span class="str">'blur'</span>, Function.createDelegate(<span class="kwrd">this</span>, <span class="kwrd">function</span>(){</pre><pre><span class="lnum">  14:  </span>       <span class="rem">//   re-enable the Timer</span></pre><pre><span class="lnum">  15:  </span>       timer._update(<span class="kwrd">true</span>, timer.get_interval()); </pre><pre><span class="lnum">  16:  </span>    }));                </pre><pre><span class="lnum">  17:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
<pre>&nbsp;</pre><pre>&nbsp;</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>Bug Fixed.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Bulk Inserting Data with the ListView Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/05/bulk_inserting_data_with_the_l.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=119" title="Bulk Inserting Data with the ListView Control" />
    <id>tag:mattberseth.com,2008://1.119</id>
    
    <published>2008-05-05T01:55:14Z</published>
    <updated>2008-05-05T01:55:48Z</updated>
    
    <summary><![CDATA[I am working on a project that needs a new screen for bulk entry tasks.&nbsp; We have a few business scenarios coming up where we have people inputting 5 to 8 records of data at a time.&nbsp; I met with a few of our analysts last week and hashed out a rough outline of what they were looking for.&nbsp; About 10 times or so during the 30 minute meeting some form of the phrase 'kind of like excel' was mentioned.&nbsp; Our data entry personnel are familiar with excel and our analysts thought an excel styled grid would make a lot of sense.&nbsp; 'An excel grid with a Submit button' was the phrase I had underlined twice in my notes.&nbsp; I wasn't too worried about the grid's styling, but I wasn't quite sure what the best way to handle the 'bulk insert' requirement.&nbsp; Most of our other grids require an explicit...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="Asp.Net" />
            <category term="ListView" />
            <category term="Prototype" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>I am working on a project that needs a new screen for bulk entry tasks.&nbsp; We have a few business scenarios coming up where we have people inputting 5 to 8 records of data at a time.&nbsp; I met with a few of our analysts last week and hashed out a rough outline of what they were looking for.&nbsp; About 10 times or so during the 30 minute meeting some form of the phrase '<strong><em>kind of like excel</em></strong>' was mentioned.&nbsp; Our data entry personnel are familiar with excel and our analysts thought an excel styled grid would make a lot of sense.&nbsp; '<em><strong>An excel grid with a Submit button' </strong></em>was the phrase I had underlined twice in my notes.&nbsp; </p> <p>I wasn't too worried about the grid's styling, but I wasn't quite sure what the best way to handle the 'bulk insert' requirement.&nbsp; Most of our other grids require an explicit mouse click to insert an item - and often times this click includes navigating the user to a separate page that is made to handle inserts.&nbsp; Of course for mass data entry tasks this can get a little old - tabbing through the cells is much nicer.&nbsp; So I took my notes back to my desk and started building a small prototype.&nbsp; You can check out the live demo to watch the grid in action.&nbsp; And a few of my implementation notes can be found under the screen shots below.</p> <p><a href="http://mattberseth2.com/bulk_insert_listview" target="_blank">Live Demo (IE6, IE7, FF, Opera)</a> | <a href="http://mattberseth2.com/downloads/bulk_edit.zip" target="_blank">Download</a></p> <p><img height="331" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_50ec485e-c8d8-49c4-8f71-79e7ca2ea153.png" width="758">&nbsp; </p> <p><strong><u>Configuring the ListView</u></strong></p> <p>My excel styled grid only has one mode - bulk insert.&nbsp; It would also support mass updating as well, but for our use cases this is a one way data stream.&nbsp; I want to use the <a href="http://msdn.microsoft.com/en-us/library/bb398790.aspx">ListView</a> because I like how the templates are structured, but the ListView doesn't natively support bulk inserting data (the ListView supports defining an <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.insertitemtemplate.aspx">InsertItemTemplate</a>, but the ListView will only render this template once - so this template isn't useful for my scenario).&nbsp; I decided I would try using the regular <a href="http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.itemtemplate.aspx">ItemTemplate</a>, but render elements that support editing instead of the usual read-only controls (i.e. TextBox's instead of Labels).&nbsp; I still use the Bind syntax because I want 2 way databinding, but because I am using the ItemTemplate for an insert scenario I will be responsible for telling the ListView when my data needs to be moved out of the controls and back to my data source.&nbsp; Below is the markup for my ListView.</p> <p><img height="761" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_8f09afdc-3445-4873-9677-bd8df463f1e0.png" width="562"> </p> <p><strong><u></u></strong>&nbsp;</p> <p><strong><u>Setting Up My DataSource</u></strong></p> <p>Next, I setup my data source.&nbsp; For this example I am using the ObjectDataSource control.&nbsp; When my data source is first bound to the ListView, I want to render placeholder objects for 8 records (i.e. I want my grid to show 8 empty rows by default).&nbsp; So when my Select method fires, I return a collection that contains 8 Customer objects that have their property values set to their default values (null strings for my example). </p> <p><img height="546" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_64ef0c17-49c2-4bac-9f6c-114fe5531797.png" width="608"> </p> <p>Next, I handle the Submit button's click event handler and loop through all of the ListViewDataItems and invoke the ListView's UpdateItem function which will cause the Update method on my ObjectDataSource to fire - moving the data back out from the controls and back into memory.&nbsp; Finally, after the data is moved back to memory, I persist the batch to the database (for the demo I am persisting it to memory, but when this page goes live it will obviously be put in the database).</p> <p><img height="286" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_6a8bc88b-0b2c-4af0-8c36-5070ed674a73.png" width="471"> </p> <p>To make sure I don't persist records with all empty values, I added a validation check to my Customer business object that makes sure the object has at least one data value before the row is submitted.&nbsp; If validation passes, I move the customer data into the database.</p> <p><img height="234" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_94c11eb5-37c2-4d3d-abee-06cd9f85ebe6.png" width="451"> </p> <p><strong><u></u></strong>&nbsp;</p> <p><strong><u>Toggling the DataTable's Skin</u></strong></p> <p>For a bit of <a href="http://en.wikipedia.org/wiki/Office_Space">flair</a> I included a couple of radio buttons for changing the grids theme from the default 2003 style excel shown below (found a nice article <a href="http://www.webdesignfromscratch.com/datasheet.cfm">here</a> on creating this skin) to the 2007 version which is a bit softer (see screen shot at the beginning of the article).&nbsp; </p> <p><img height="333" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_bbb389ef-3719-4024-9cd1-8780b87379eb.png" width="758"> </p> <p>To change the grids skin I attached event handler's to the radio button's click events and use the <a href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementAddCssClassMethod.aspx">Sys.UI.DomElement.addCssClass</a> and <a href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementRemoveCssClassMethod.aspx">removeCssClass</a> to toggle the CSS class that is applied to the grid.&nbsp; Below is the JavaScript that does this bit of work for me.&nbsp; </p> <p><img height="709" alt="image" src="http://mattberseth.com/WindowsLiveWriter/ExcelDataSheetStyledDataGrid_11D2E/image_a22fe664-4646-4466-bed4-5892b63c080a.png" width="641"> </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Master-Detail with the GridView, DetailsView and ModalPopup Controls</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/masterdetail_with_the_gridview.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=118" title="Master-Detail with the GridView, DetailsView and ModalPopup Controls" />
    <id>tag:mattberseth.com,2008://1.118</id>
    
    <published>2008-04-30T01:36:47Z</published>
    <updated>2008-04-30T01:37:34Z</updated>
    
    <summary><![CDATA[A while back I wrote a post describing how the DetailsView, GridView, UpdatePanel and the AjaxControlToolkit's ModalPopup controls could be used to implement the common Master/Details UI pattern.&nbsp; I cheated a bit when creating my original example in that I didn't really complete the implementation - the Save button on the popup didn't actually do anything.&nbsp; Since writing that post I have received a lot of email and a number of people left comments asking me to complete the example - so here it is.&nbsp; If you plan on reading through this article, I recommend playing around with the demo site to get a feel for how the page works.&nbsp; All data changes are only persisted to memory, so don't worry about messing up the data set. Live Demo | Download Scenario I am sure everyone is pretty familiar with Master/Details style of editing data, but just in case -...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="AjaxControlToolkit" />
            <category term="Asp.Net" />
            <category term="GridView" />
            <category term="ModalPopupExtender" />
            <category term="UpdatePanel" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>A while back I wrote a <a href="http://mattberseth.com/blog/2007/07/modalpopupextender_example_for.html">post</a> describing how the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview.aspx">DetailsView</a>, <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.aspx">GridView</a>, <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.updatepanel.aspx">UpdatePanel</a> and the <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/samples/">AjaxControlToolkit's</a> <a href="http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ModalPopup/ModalPopup.aspx">ModalPopup</a> controls could be used to implement the common Master/Details UI pattern.&nbsp; I cheated a bit when creating my original example in that I didn't really complete the implementation - the Save button on the popup didn't actually do anything.&nbsp; Since writing that post I have received a lot of email and a number of people left comments asking me to complete the example - so here it is.&nbsp; If you plan on reading through this article, I recommend playing around with the demo site to get a feel for how the page works.&nbsp; All data changes are only persisted to memory, so don't worry about messing up the data set.</p> <p><a href="http://mattberseth2.com/master_details_II/" target="_blank">Live Demo</a> | <a href="http://mattberseth2.com/downloads/master_details_II.zip" target="_blank">Download</a></p> <p><img height="280" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_32277640-7fe2-49d2-98f5-036ded667041.png" width="604"></p> <p><strong><u>Scenario</u></strong></p> <p>I am sure everyone is pretty familiar with Master/Details style of editing data, but just in case - here is how my page works.&nbsp; The grid shows 12 rows of customer data.&nbsp; The far right column in the grid contains a hyperlink that when clicked brings the detail view of the row into focus so the corresponding row can be edited.&nbsp; The detail view is a popup control and contains a Save and Close buttons.&nbsp; When close is clicked, the detail popup is dismissed and the user goes back to viewing the main grid.&nbsp; When they click Save, some simple validation checks are run (all are <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.requiredfieldvalidator.aspx">RequiredFieldValidators</a> for this sample) and the new data values are persisted, and finally the detail popup is dismissed and the main grid is refreshed so that it displays the changes.</p> <p><strong><u>Controls</u></strong></p> <p>There are quite a few controls that work together for this sample.&nbsp; Here is a listing of the controls and the role they play.</p> <table cellspacing="0" cellpadding="2" width="684" border="1"> <tbody> <tr> <td valign="top" width="199"><strong>Control</strong></td> <td valign="top" width="483"><strong>Role</strong></td></tr> <tr> <td valign="top" width="199"><a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.aspx">GridView</a></td> <td valign="top" width="483">Display the 12 customer rows of data</td></tr> <tr> <td valign="top" width="199"><a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview.aspx">DetailsView</a></td> <td valign="top" width="483">Display the single customer row that is currently being edited</td></tr> <tr> <td valign="top" width="199"><a href="http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ModalPopup/ModalPopup.aspx">ModalPopupExtender</a></td> <td valign="top" width="483">Display the DetailView modally</td></tr> <tr> <td valign="top" width="199"><a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.updatepanel.aspx">UpdatePanel</a></td> <td valign="top" width="483">Allow the DetailView to be loaded without refreshing the entire page</td></tr> <tr> <td valign="top" width="199"><a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.objectdatasource.aspx">ObjectDataSource</a></td> <td valign="top" width="483">Manage how our UI interacts with the customer data</td></tr></tbody></table> <p><strong><u>Customer GridView</u></strong></p> <p>The Customer Grid is just a regular GridView.&nbsp; I have used BoundFields to bind to the data and I am using a TemplateField for rendering the 'Edit' anchor.&nbsp; </p> <p><img height="403" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_dfbf5c3c-c7bb-4eeb-b7ec-f888a04eddce.png" width="794"> </p> <p>When 'Edit' is clicked, I want to show the detail view popup.&nbsp; To accomplish this I set the CommandName of the 'Edit' button to Select - this will cause the SelectedIndexChanged event to fire on the server.&nbsp; Inside this event handler, I force the DetailView to databind, passing the datasource it is bound to the ID that corresponds to the row the user clicked.&nbsp; Finally, I let the UpdatePanel the DetailView is contained in that it needs to update its contents and invoke the Show server side method of my ModalPopupExtender which will cause the popup to be displayed when the partial page is reloaded on the client.</p> <p>Here are the 2 events handlers that I am using to accomplish this bit of work.&nbsp; The top event handler fires when 'Edit' is clicked and the explicit call to DataBind forces the DetailView's corresponding ObjectDataSource's Selecting event to fire.&nbsp; In this handler I use the SelectedIndex of the GridView to fetch the ID the data source needs.&nbsp; </p> <p><img height="305" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_8c976986-e4bf-415a-bf0c-06238aab78a1.png" width="634"> </p> <p><img height="219" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_3589db53-32d1-4564-a735-ed50739785fd.png" width="797">&nbsp; </p> <p><strong><u>Customer DetailsView</u></strong></p> <p>The DetailsView for the individual customer records is also pretty simple - except because I have included RequiredFieldValidators I wasn't able to use the BoundFields and instead I had to explicitly define the EditItemTemplate for each of the fields. </p> <p><img height="402" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_71591cea-672c-4881-bf7d-619526fa3bfe.png" width="726"> </p> <p>Just below the DetailsView, I have 2 buttons that interact with the ModalPopupExtender.&nbsp; The Close button dismissed the popup without posting back or committing any changes.&nbsp; The Save button does post back, moves the data out of the DetailsView and back to the ObjectDataSource, hides the ModalPopupExtender and finally causes the main GridView to refresh so it displays the changes.</p> <p><img height="367" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_50060c66-6398-4171-9772-c80699506635.png" width="789"> </p> <p>Here is the logic I have wired to the Save button's click handler.</p> <p><img height="391" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_52e21c59-ffbd-4158-a465-fcf9e9f76e4b.png" width="513"> </p> <p><strong><u>Apply a Yellow Fade to the Updated Row in the GridView</u></strong></p> <p>And while this has been pretty much nuts and bolds functionality thus far, I couldn't resist trying to spice it up by applying a yellow fade to the row in the main grid that was updated.&nbsp; To implement this feature, I needed a way to send a bit of information back from the server that let me know what row in the grid was updated.&nbsp; So my approach was to use the <a href="http://msdn2.microsoft.com/en-us/library/bb398863.aspx">ScriptManager's</a> <a href="http://msdn.microsoft.com/en-us/library/bb359752.aspx">RegisterDataItem</a> method to accomplish this.&nbsp; Here is the doc from MSDN:</p> <blockquote> <p><strong><em>Sends custom data to a control during partial-page rendering, and indicates whether the data is in JavaScript Object Notation (JSON) format.</em></strong></p></blockquote> <p>Just what I need - so after the Save button is clicked, back in the server side event handler, I call RegisterDataItem and pass the index of the updated row to the GridView.&nbsp; Then after the partial refresh has occurred back on the client, I extract the row index from the DataItem's collection, use it to find the row that changed and give it a custom CSS class.</p> <p>So I added the following call to my Save button handler to register the index of the row that was changed.</p> <p><img height="153" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_d86d84d2-471f-48b5-93cc-2d2e5dbebc55.png" width="515"></p> <p>And then added the following JavaScript to my page to track down the corresponding TR element in the rendered table and apply the <em>updated</em> CSS class to the row.</p> <p><img height="471" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_6e3b2e07-0d48-4574-a1d9-d4211b9419c3.png" width="617">&nbsp; </p> <p>And like magic I get a yellow background applied to the row that was edited.&nbsp; The background color stays in place for 1.5 seconds then my timeout handler fires and removes it.&nbsp; A poor man's animation, but the plumbing is in place for me to improve upon.&nbsp; Below are the screen shots of how it looks.</p> <p><img height="265" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_d076f72d-8773-4919-858c-6b53dee04afc.png" width="569"> </p> <p><img height="147" alt="image" src="http://mattberseth.com/WindowsLiveWriter/958e288a8eb2_11AC8/image_1f1736fc-7169-4871-819a-cfef0ea248f2.png" width="559"> </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>AjaxControlToolkit TabContainer Theme Gallery</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/ajaxcontroltoolkit_tabcontaine.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=117" title="AjaxControlToolkit TabContainer Theme Gallery" />
    <id>tag:mattberseth.com,2008://1.117</id>
    
    <published>2008-04-25T01:55:51Z</published>
    <updated>2008-04-25T01:56:18Z</updated>
    
    <summary><![CDATA[I created a new theme for the AjaxControlToolkit's TabContainer&nbsp; control and I was going to write a post discussing how I did it.&nbsp; But as I was creating the post I realized that I have really written about all of the details before (see my TabContainer Archive page).&nbsp; So instead of repeating myself, I decided I would instead put together a post that catalogs the Tab themes I have created so far and pull of them together into a single demo site that showcases each of these themes.&nbsp; I plan on adding to the gallery as well as this post as new themes are added.&nbsp; If I like how it works I might create similar pages for some of my favorite ListView and GridView themes as well.&nbsp;&nbsp; Live Demo (IE6, IE7, FF and Opera) | Download &nbsp; Google Analytics Theme Opera Theme LinkedIn Blue Theme LinkedIn Gray Theme Gray Theme...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="AjaxControlToolkit" />
            <category term="Gallery" />
            <category term="TabContainer" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>I created a new theme for the <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/">AjaxControlToolkit's</a> <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/samples/Tabs/Tabs.aspx">TabContainer</a>&nbsp; control and I was going to write a post discussing how I did it.&nbsp; But as I was creating the post I realized that I have really written about all of the details before (see my <a href="http://mattberseth.com/blog/tabcontainer/" target="_blank">TabContainer Archive page</a>).&nbsp; So instead of repeating myself, I decided I would instead put together a post that catalogs the Tab themes I have created so far and pull of them together into a single demo site that showcases each of these themes.&nbsp; I plan on adding to the gallery as well as this post as new themes are added.&nbsp; If I like how it works I might create similar pages for some of my favorite <a href="http://mattberseth.com/blog/listview/">ListView</a> and <a href="http://mattberseth.com/blog/gridview/">GridView</a> themes as well.&nbsp;&nbsp; </p> <p><a href="http://mattberseth2.com/tab_gallery/" target="_blank">Live Demo (IE6, IE7, FF and Opera)</a> | <a href="http://mattberseth2.com/downloads/tab_gallery.zip" target="_blank">Download</a></p> <p>&nbsp;</p> <p><strong>Google Analytics Theme</strong></p> <p><img height="177" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_bf3411d0-eaca-4944-b499-67de632d18b6.png" width="447"> </p> <p><strong>Opera Theme</strong></p> <p><img height="186" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_b5703472-a759-472d-a28a-704385c42506.png" width="447"> </p> <p><strong>LinkedIn Blue Theme</strong> </p> <p><img height="181" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_d7a2c1be-659d-40e8-bc86-db09f052e08e.png" width="447"> </p> <p><strong>LinkedIn Gray Theme</strong> </p> <p><img height="176" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_def653d8-e319-4b08-8d86-97e6912e9651.png" width="443"> </p> <p><strong>Gray Theme</strong></p> <p><img height="165" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_48d762bb-ae8b-442e-8763-84af9619a424.png" width="443"> </p> <p><strong>YUI Theme</strong></p> <p><img height="187" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_0acc55ce-a465-4db4-9300-eabf9a6d80c8.png" width="444"> </p> <p><strong>Soft-Green Theme</strong></p> <p><img height="185" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_26aa6c1f-4057-41d7-b2ee-c4ca53037ae6.png" width="446"> </p> <p><strong>Fancy-Blue Theme</strong></p> <p><img height="204" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_7ef12c63-fb5e-4aa7-a78c-0bb1fde3b9cb.png" width="446"> </p> <p><strong>Fancy-Green Theme</strong></p> <p><img height="203" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_e2db0107-5e82-448b-bd0f-8978e27e5c64.png" width="446"> </p> <p><strong>Fancy-Orange Theme</strong></p> <p><img height="199" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_3501b291-ca0f-47b5-9357-a2e268ad538e.png" width="451"> </p> <p><strong>Fancy-Purple Theme</strong></p> <p><img height="197" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_86ae3cb3-d6d1-4512-9342-fb74ae03883a.png" width="444"> </p> <p><strong>Fancy-Red Theme</strong></p> <p><img height="202" alt="image" src="http://mattberseth.com/WindowsLiveWriter/AjaxControlToolkitTabContainerThemeLibra_1226B/image_d02291c2-eef6-499a-bf4f-bde2b7ac41a1.png" width="448"></p>]]>
        
    </content>
</entry>
<entry>
    <title>3 Tips for Working with the AjaxControlToolkit&apos;s TabContainer Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/3_tips_for_working_with_the_aj.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=116" title="3 Tips for Working with the AjaxControlToolkit's TabContainer Control" />
    <id>tag:mattberseth.com,2008://1.116</id>
    
    <published>2008-04-10T02:04:51Z</published>
    <updated>2008-04-10T02:05:32Z</updated>
    
    <summary><![CDATA[Here are three quick tips you might find useful when using the Toolkit's Tab control.&nbsp; I included demo's for all three tips so you can get a feel for how it looks and behaves. Live Demo (IE6, IE7, FF, Opera) | Download &nbsp; #1: How To Change the Selected Tab When the Tab Header is MousedOver By default the tab control will switch the selected tab when a different tabs' header is clicked.&nbsp; Depending upon the content you are displaying, you might find it useful to change the selected tab as the user mouses over a different tab.&nbsp; I saw an example of this on designflavr.com.&nbsp; This site has a tab control that displays the categories and tags and some other miscellaneous links.&nbsp; These items are collected into a tab control that has been placed in the right hand sidebar.&nbsp; You can get this mouseover style navigation by adding only...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="AjaxControlToolkit" />
            <category term="Asp.Net" />
            <category term="TabContainer" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>Here are three quick tips you might find useful when using the <a href="http://www.asp.net/ajax/ajaxcontroltoolkit/samples/">Toolkit's</a> <a href="http://www.asp.net/AJAX/AjaxControlToolkit/Samples/Tabs/Tabs.aspx">Tab control</a>.&nbsp; I included demo's for all three tips so you can get a feel for how it looks and behaves.</p> <p><a href="http://mattberseth2.com/tab_tricks/" target="_blank">Live Demo (IE6, IE7, FF, Opera)</a> | <a href="http://mattberseth2.com/downloads/tab_tricks.zip" target="_blank">Download</a></p> <p>&nbsp;</p> <h4><strong><u>#1: How To Change the Selected Tab When the Tab Header is MousedOver</u></strong></h4> <p>By default the tab control will switch the selected tab when a different tabs' header is clicked.&nbsp; Depending upon the content you are displaying, you might find it useful to change the selected tab as the user mouses over a different tab.&nbsp; I saw an example of this on <a href="http://www.designflavr.com/">designflavr.com</a>.&nbsp; This site has a tab control that displays the categories and tags and some other miscellaneous links.&nbsp; These items are collected into a tab control that has been placed in the right hand sidebar.&nbsp; </p> <p>You can get this mouseover style navigation by adding only a few lines of JavaScript to your page.&nbsp; And the logic is very simple:</p> <ol> <li>get a reference to each of the tab panels  <li>attach an event handler to the tab header's mouseover event  <li>when the mouseover event fires, set it as the selected tab</li></ol> <p>Here is the chunk of JavaScript you can use to implement this.&nbsp; I put it in the pageLoad so it runs when the page spins up.</p> <p><img height="370" alt="image" src="http://mattberseth.com/WindowsLiveWriter/b454709fe1c9_12C4E/image_dd4fd198-9953-43cb-915a-04178f82f2d1.png" width="528"> </p> <p>&nbsp;</p> <h4><strong><u>#2: How To Change the Selected Tab Using Navigation Buttons</u></strong></h4> <p>And for other scenarios, you might want to use an input element like a button or something to control the tabs navigation - something like next and previous buttons for cycling through the tabs.&nbsp; To handle this scenario, you can use the bit of JavaScript below.&nbsp; If you wire this to the input elements click event, it will take care of advancing the selected.&nbsp; I even included <em>wrap around</em> logic for handling the scenario where the last tab is selected and the user clicks the next button.&nbsp; Again, nothing too fancy here, just some simple math for calculating the index of the next page and a few calls to the TabContainer's JavaScript components.&nbsp;&nbsp;&nbsp; </p> <p>Here is the JavaScript function that handles this scenario ...</p> <p><img height="607" alt="image" src="http://mattberseth.com/WindowsLiveWriter/b454709fe1c9_12C4E/image_ce1c59ef-8d95-4410-b213-f978a25654a6.png" width="484"> </p> <p>And this is how you can bind it to a Next and Previous buttons ...</p> <p><img height="200" alt="image" src="http://mattberseth.com/WindowsLiveWriter/b454709fe1c9_12C4E/image_b17e4e49-3a09-4ea6-84c3-ef315dea8d57.png" width="453"> </p> <h4><strong><u>#3: How to Center the Tab Headers Horizontally</u></strong></h4> <p>Last tip - you want to center the tab headers like so ...</p> <p><img height="102" alt="image" src="http://mattberseth.com/WindowsLiveWriter/b454709fe1c9_12C4E/image_8b96564b-d3d6-48d4-8e83-e83a54799c0a.png" width="344"></p> <p>Just set the text-align of the .ajax__tab_header class to center.&nbsp; </p> <p>&nbsp;<img height="95" alt="image" src="http://mattberseth.com/WindowsLiveWriter/b454709fe1c9_12C4E/image_bbaa3f53-d81d-4e82-bcf2-0ce60175c3c4.png" width="209"> </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Using a DataPager with the GridView Control - Implementing IPageableItemContainer</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/using_a_datapager_with_the_gri.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=115" title="Using a DataPager with the GridView Control - Implementing IPageableItemContainer" />
    <id>tag:mattberseth.com,2008://1.115</id>
    
    <published>2008-04-09T01:26:41Z</published>
    <updated>2008-04-09T01:27:06Z</updated>
    
    <summary><![CDATA[One of the new controls that shipped with ASP.NET 3.5 is the DataPager.&nbsp; It's a flexible control that renders the paging elements data-bound controls that implement the IPageableItemContainer interface (currently only the ListView control).&nbsp; The big change with the DataPager is that it is decoupled from the data-bound control it provides paging support for.&nbsp; It can be embedded somewhere within the data-bound control's control hierarchy (like contained within the LayoutTemplate of the ListView), but it doesn't have to - It can exist on its own outside of the data-bound control as well. When I was writing my last post, I kind of wished the 3.5 GridView implemented the IPageableItemContainer interface.&nbsp; It sure would have made things simpler for me.&nbsp; So I thought I would take a shot at extending the GridView myself.&nbsp; Read on for the details. Live Demo (IE6, IE7, FF, Opera) | Download&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Implementing IPageableItemContainer This is a...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="Asp.Net" />
            <category term="DataPager" />
            <category term="GridView" />
            <category term="Prototype" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>One of the new controls that shipped with ASP.NET 3.5 is the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.datapager.aspx">DataPager</a>.&nbsp; It's a flexible control that renders the paging elements data-bound controls that implement the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.ipageableitemcontainer.aspx">IPageableItemContainer</a> interface (currently only the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.aspx">ListView</a> control).&nbsp; The big change with the DataPager is that it is decoupled from the data-bound control it provides paging support for.&nbsp; It can be embedded somewhere within the data-bound control's control hierarchy (like contained within the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.layouttemplate.aspx">LayoutTemplate</a> of the ListView), but it doesn't have to - It can exist on its own outside of the data-bound control as well.</p> <p>When I was writing <a href="http://mattberseth.com/blog/2008/04/building_a_vs2008_styled_grid_1.html">my last post</a>, I kind of wished the 3.5 <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.aspx">GridView</a> implemented the IPageableItemContainer interface.&nbsp; It sure would have made things simpler for me.&nbsp; So I thought I would take a shot at extending the GridView myself.&nbsp; Read on for the details.</p> <p><a href="http://mattberseth2.com/gridivew_datapager/" target="_blank">Live Demo (IE6, IE7, FF, Opera)</a> | <a href="http://mattberseth2.com/downloads/gridivew_datapager.zip" target="_blank">Download</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p> <p><img height="372" alt="image" src="http://mattberseth.com/WindowsLiveWriter/UsingaDataPagerwiththeGridViewControl_11903/image_815c201f-987c-4fc0-97c8-5fc2f327babc.png" width="743"> </p> <h4><strong><u>Implementing IPageableItemContainer</u></strong></h4> <p>This is a pretty simple interface - 2 properties, a method and an event.&nbsp; But I didn't even try to implement it on my own!&nbsp; Instead I opened <a href="http://www.aisto.com/roeder/dotnet/">Reflector</a> and took a peek at the ListView's implementation.&nbsp; </p> <p>Here is the specification of the IPageableItemContainer interface.&nbsp;&nbsp; </p> <p><img height="606" alt="image" src="http://mattberseth.com/WindowsLiveWriter/UsingaDataPagerwiththeGridViewControl_11903/image_ce926ff1-8a6d-4e02-95d4-4a8abb7c8634.png" width="719">&nbsp;</p> <p>I implemented the MaximumRows getter to return the GridView's PageSize value and had the StartRowIndex return the PageSize multiplied by the PageIndex.&nbsp; For the TotalRowCountAvailable event, I followed the same pattern the other controls use for declaring events.&nbsp; It is a little weird if you haven't seen this syntax before, but it uses less memory and is the pattern the other web controls use so I followed it.</p> <p><img height="438" alt="image" src="http://mattberseth.com/WindowsLiveWriter/UsingaDataPagerwiththeGridViewControl_11903/image_4e011772-7801-4b40-b23a-1cfca612107a.png" width="724"> </p> <p>The SetPageProperties method is only mildly more difficult (again with the help of the ListView's implementation as a reference).&nbsp; When the SetPageProperties method is invoked, it is passed the new startRowIndex, the new pageSize (what the DataPager refers to as maxmimumRows) and a boolean value that is true if the control needs to be rebound after the properties are set.&nbsp; Armed with these new values, my SetPageProperties implementation updates the GridView's PageSize and PageIndex properties and raises the PageIndexChanging and PageIndexChanged events along the way.</p> <p><img height="655" alt="image" src="http://mattberseth.com/WindowsLiveWriter/UsingaDataPagerwiththeGridViewControl_11903/image_58e23d25-ab69-4d5f-8e27-51cc3155f624.png" width="682"> </p> <h4><strong><u>Override GridView.CreateChildControls</u></strong></h4> <p>After the interface is implemented, the only thing that remains is figuring out when my new GridView needs to raise the TotalRowCountAvailable event.&nbsp; It turns out the CreateChildControls method is where the ListView control raises this event (again, figured out that using <a href="http://www.aisto.com/roeder/dotnet/">Reflector</a> and taking a look at how the ListView control does it).&nbsp; So I overrode the CreateChildControls method in my new GridView class and added logic that raises the TotalRowCountAvailable event.&nbsp; After the event is raised, I go ahead and make sure the GridView isn't rendering the pager rows.&nbsp; Note: my extended GridView doesn't support the standard GridView paging rows anymore, only the DataPager is supported.&nbsp; This is why I have made sure the pager rows are not visible.</p> <p>&nbsp;<img height="641" alt="image" src="http://mattberseth.com/WindowsLiveWriter/UsingaDataPagerwiththeGridViewControl_11903/image_65f04b9a-a439-4b86-a502-abbe66ffe6cd.png" width="722"> </p> <h4><strong><u>Is This Really All That Useful?</u></strong></h4> <p>I think it might be.&nbsp; Sometime in the next year, one of the projects I am working on will be converting from ASP.NET 2.0 to 3.5.&nbsp; If I had to guess I would say we have somewhere around 75 or so GridViews and a ton of GridView specific code for viewing, inserting, updating and deleting records that has already been written and tested.&nbsp; Having the GridView implement IPageableItemContainer gives me flexibility and provides me choices when we start the migration project - I can keep all of my GridView code, but completely change the way we present our paging elements.&nbsp; </p> <p>I am not sure if we will actually go this route, but I figured I would post it - just in case someone else can improve or make use of it.</p> <p>That's it.&nbsp; Enjoy!&nbsp;&nbsp; </p> <p><strong>P.S&nbsp; I have another vacation coming up.&nbsp; This time I am on to Augusta to watch the <a href="http://www.masters.org/en_US/index.html">Masters</a> and then some more traveling the following week.&nbsp; So things will probably go quiet around here for the next few weeks.&nbsp; </strong></p>]]>
        
    </content>
</entry>
<entry>
    <title>Building a VS2008 Styled Grid with the GridView Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/building_a_vs2008_styled_grid_1.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=114" title="Building a VS2008 Styled Grid with the GridView Control" />
    <id>tag:mattberseth.com,2008://1.114</id>
    
    <published>2008-04-07T01:37:51Z</published>
    <updated>2008-04-07T01:38:18Z</updated>
    
    <summary><![CDATA[I received some positive feedback from my most recent post describing how to create a VS 2008 styled datagrid by using ASP.NET's ListView and DataPager controls.&nbsp; A few people left comments, but I also received a handful of emails asking how to achieve this same look using the GridView.&nbsp; So while this VS style skin was still fresh in my mind I thought I would write up a quick post on it.&nbsp; Live Demo (IE6, IE7, FF and Opera) | Download &nbsp;&nbsp; Sorting To apply the custom sorting icon to the datagrid's header, I used the GridView's RowDataBound event to apply a custom CSS class to the header cell.&nbsp; I then use the background image style to apply the sorting icon to the right of the header text. &nbsp; Border Just like in my previous post, I use a series of DIV's to define the datatables frame.&nbsp; I then use...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="Asp.Net" />
            <category term="GridView" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>I received some positive feedback from <a href="http://mattberseth.com/blog/2008/04/building_a_vs2008_styled_grid.html">my most recent post</a> describing how to create a VS 2008 styled datagrid by using ASP.NET's <a href="http://msdn2.microsoft.com/en-us/library/bb398790.aspx">ListView</a> and <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.datapager.aspx">DataPager</a> controls.&nbsp; A few people left comments, but I also received a handful of emails asking how to achieve this same look using the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.aspx">GridView</a>.&nbsp; So while this VS style skin was still fresh in my mind I thought I would write up a quick post on it.&nbsp; </p> <p><a href="http://mattberseth2.com/vs2008_styled_gridview/" target="_blank">Live Demo (IE6, IE7, FF and Opera)</a> | <a href="http://mattberseth2.com/downloads/vs2008_styled_gridview.zip" target="_blank">Download</a></p> <p><img height="421" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_4b5c5b83-4b68-40ce-92de-d8ba194a41d3.png" width="738">&nbsp;&nbsp; </p> <h4><strong><u>Sorting</u></strong></h4> <p>To apply the custom sorting icon to the datagrid's header, I used the GridView's RowDataBound event to apply a custom CSS class to the header cell.&nbsp; I then use the background image style to apply the sorting icon to the right of the header text.</p> <p><img height="612" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_c632b6a4-41dd-4768-9d3a-c78afa3985b5.png" width="612">&nbsp;</p> <h4><strong><u>Border</u></strong></h4> <p>Just like <a href="http://mattberseth.com/blog/2008/04/building_a_vs2008_styled_grid.html">in my previous post</a>, I use a series of DIV's to define the datatables frame.&nbsp; I then use CSS to apply background images to these DIVs.&nbsp; Put it all together and you get a sweet looking border.</p> <p><img height="266" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_94e5bc55-293b-49d8-ba12-e829ec7308ee.png" width="606">&nbsp; </p> <h4><strong><u>Pager Style and Settings</u></strong></h4> <p>The GridView control allows you to customize how the pager controls look by using the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.pagersettings.aspx">PagerSettings</a> element (if you require even more customization you can use the <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.pagertemplate.aspx">PagerTemplate</a>).&nbsp; It supports a handful of modes and provides other attributes that can be used to change the appearance of the pager row.&nbsp; Here is a table that describes the supported modes of the PagerSettings&nbsp; </p> <p><img height="214" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_90921204-1a94-41fd-af9c-01f9e4fbef15.png" width="644"> </p> <p>Unfortunately, there isn't a NextPreviousFirstLastNumeric mode, because that is actually the one I would use.&nbsp; However, the NumericFirstLast mode is pretty close so that is what I used to configure my grid.</p> <p><img height="98" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_1de234a6-57b9-4186-ba13-00681355e461.png" width="411"></p> <h4><strong><u>Put it All Together</u></strong></h4> <p>And here is the markup for my GridView.&nbsp; </p> <p><img height="726" alt="image" src="http://mattberseth.com/WindowsLiveWriter/fba47470eb3b_11700/image_ced58b3c-4cf7-4ad8-9173-67d671c8e0fd.png" width="645">&nbsp;&nbsp; </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Building a VS2008 Styled Grid with the ListView and DataPager Controls</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/04/building_a_vs2008_styled_grid.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=113" title="Building a VS2008 Styled Grid with the ListView and DataPager Controls" />
    <id>tag:mattberseth.com,2008://1.113</id>
    
    <published>2008-04-02T01:46:52Z</published>
    <updated>2008-04-02T01:47:27Z</updated>
    
    <summary><![CDATA[I took a break from my recent Silverlight explorations to work on a new datagrid skin.&nbsp; I thought the skin turned out fairly well so I figured I would pass it along just in case anyone else could find a use for it.&nbsp; Like some of my other skins, it makes use of ASP.NET 3.5's ListView, DataPager and LinqDataSource controls.&nbsp; Here is the run down of the features ...&nbsp;&nbsp;&nbsp; VS 2008 style border blue border&nbsp; Vimeo-ish style data pager Row hover effects (except for IE6) Sort icons Live Demo (IE6, IE7, FF, Opera) | Download VS 2008 Style Border To create the border, I used a variation of the rounded corners technique Josh outlines here.&nbsp; Below is the markup.&nbsp; It is pretty much just a handful of DIV elements that are used for holding the images.&nbsp; If you are thinking about using this technique, you should check out Josh's site...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="ASP.NET AJAX" />
            <category term="Asp.Net" />
            <category term="DataPager" />
            <category term="LinqDataSource" />
            <category term="ListView" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>I took a break from my recent <a href="http://mattberseth.com/blog/silverlight_2/">Silverlight explorations</a> to work on a new datagrid skin.&nbsp; I thought the skin turned out fairly well so I figured I would pass it along just in case anyone else could find a use for it.&nbsp; Like some of my other skins, it makes use of ASP.NET 3.5's <a href="http://msdn2.microsoft.com/en-us/library/bb398790.aspx">ListView</a>, <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.datapager.aspx">DataPager</a> and <a href="http://msdn2.microsoft.com/en-us/library/bb547113.aspx">LinqDataSource</a> controls.&nbsp; </p> <p>Here is the run down of the features ...&nbsp;&nbsp;&nbsp; </p> <ul> <li>VS 2008 style border blue border&nbsp; <li>V<a href="http://www.vimeo.com/">imeo</a>-ish style data pager  <li>Row hover effects (except for IE6)  <li>Sort icons</li></ul> <p><a href="http://mattberseth2.com/vs2008_datatable_skin/" target="_blank">Live Demo (IE6, IE7, FF, Opera)</a> | <a href="http://mattberseth2.com/downloads/vs2008_datatable_skin.zip">Download</a></p> <p><img height="384" alt="image" src="http://mattberseth.com/WindowsLiveWriter/VS2008ListViewSkin_11984/image_6e301f55-593c-4e6e-97c8-ae1c998e48d3.png" width="737"> </p> <h4><u><strong>VS 2008 Style Border</strong></u></h4> <p>To create the border, I used a variation of the rounded corners technique <a href="http://blog.josh420.com/">Josh</a> outlines <a href="http://blog.josh420.com/archives/2007/11/how-to-create-fluid-width-div-layers-with-rounded-corners.aspx">here</a>.&nbsp; Below is the markup.&nbsp; It is pretty much just a handful of DIV elements that are used for holding the images.&nbsp; If you are thinking about using this technique, you should check out Josh's site to get the run down.&nbsp; After you finish that you can check out this <a href="http://mattberseth.com/blog/2008/02/building_sleek_soft_and_simple.html">post</a> to see how it can applied to place a border around a datagrid. </p><pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="rounded"</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="top-outer"</span><span class="kwrd">&gt;&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="top-inner"</span><span class="kwrd">&gt;<span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="top"</span><span class="kwrd">&gt;</span>&lt;/</span><span class="html">div</span><span class="kwrd">&gt;&lt;/</span><span class="html">div</span><span class="kwrd">&gt;<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span> </span>
    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="mid-outer"</span><span class="kwrd">&gt;&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="mid-inner"</span><span class="kwrd">&gt;<span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="mid"</span><span class="kwrd">&gt;</span></span>
        <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="content"</span><span class="kwrd">&gt;</span>
            <span class="rem">&lt;!--Content goes here--&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;&lt;/</span><span class="html">div</span><span class="kwrd">&gt;<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></span>
    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="bottom-outer"</span><span class="kwrd">&gt;&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="bottom-inner"</span><span class="kwrd">&gt;<span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="bottom"</span><span class="kwrd">&gt;</span>&lt;/</span><span class="html">div</span><span class="kwrd">&gt;&lt;/</span><span class="html">div</span><span class="kwrd">&gt;<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span></pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>And here are the images I have mapped to the above DIV tags.&nbsp; I zoomed in a bit on the images so you could get a better idea of how they make up the border.&nbsp; </p>
<table cellspacing="0" cellpadding="2" width="400" border="1">
<tbody>
<tr>
<td align="middle" width="133"><img height="69" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/tl.gif" width="27"></td>
<td align="middle" width="133"><img height="65" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/tm.gif" width="106"> </td>
<td align="middle" width="133"><img height="66" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/tr.gif" width="26"> </td></tr>
<tr>
<td align="middle" width="133"><img height="64" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/l.gif" width="36"> </td>
<td align="middle" width="133">Content Goes Here!</td>
<td align="middle" width="133"><img height="55" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/r.gif" width="31"> </td></tr>
<tr>
<td align="middle" width="133"><img height="44" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/bl.gif" width="50"> </td>
<td align="middle" width="133"><img height="44" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/bm.gif" width="105"> </td>
<td align="middle" width="133"><img height="41" src="http://mattberseth2.com/vs2008_datatable_skin/_assets/img/br.gif" width="46"> </td></tr></tbody></table>
<p>&nbsp;</p>
<h4><strong><u>Vimeo-ish Style Data Pager</u></strong></h4>
<p>The data pager is roughly based on the one found on <a href="http://www.vimeo.com/">Vimeo</a>'s site.&nbsp; Again, nothing too much new here except the mouse over effects.&nbsp; I personally love this style of pager - it looks great AND it doesn't require any images.</p>
<p><img height="79" alt="image" src="http://mattberseth.com/WindowsLiveWriter/VS2008ListViewSkin_11984/image_d4c0b4b2-f547-415e-8fc1-69ab67a5d63e.png" width="319">&nbsp; </p>
<h4><strong><u>Row Hover Effects</u></strong></h4>
<p>Finally, I used the hover pseudo class to make the mouseover row stand out a little bit.&nbsp; To help differentiate it from the other rows I added a blue triangle to the rows first cell, changed the font color from #666 to #000 and applied a light yellow background.</p>
<p><img height="126" alt="image" src="http://mattberseth.com/WindowsLiveWriter/VS2008ListViewSkin_11984/image_25a30049-4505-42a0-8313-ef0406f869aa.png" width="733"> </p>
<p>To apply the triangle to the first cell, I used the ListView's ItemTemplate to apply the <strong><em>first </em></strong>class to the first TD of each data row.&nbsp; </p>
<p><img height="199" alt="image" src="http://mattberseth.com/WindowsLiveWriter/VS2008ListViewSkin_11984/image_13c351b2-f858-429b-a6ad-56a070fef26f.png" width="539"> </p>
<p>Then, I could use this class in combination with the hover pseudo class to get the triangle to appear only when the row is moused over.</p>
<p><img height="112" alt="image" src="http://mattberseth.com/WindowsLiveWriter/VS2008ListViewSkin_11984/image_38188c62-7318-4102-afca-f6a5c5706aa5.png" width="385"> </p>
<p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Sorting with Silverlight 2&apos;s DataGrid Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/03/sorting_with_silverlight_2s_da.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=112" title="Sorting with Silverlight 2's DataGrid Control" />
    <id>tag:mattberseth.com,2008://1.112</id>
    
    <published>2008-03-27T00:06:38Z</published>
    <updated>2008-03-27T00:06:55Z</updated>
    
    <summary><![CDATA[So I am just starting to get my feet wet with Silverlight 2.&nbsp; I have gained some confidence over the past few days, but on the crawl, walk, run scale it feels like I am still crawling.&nbsp; Beginner or not, I figured I would take a shot at getting Silverlight's DataGrid control to support sorting.&nbsp; Nothing too complicated - just the standard click on the column header to sort the data.&nbsp; Surprisingly, I didn't see much on MSDN talking about how to implement sorting using the DataGrid.&nbsp; I know the documentation is still in the works so I am sure it is coming, but I was a little bit concerned about how to get started.&nbsp; No worries though, it turned out to be a breeze.&nbsp; If you are interested in the details, I have a quick description of what I did just beneath the following screen shot. Live Demo |...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="Silverlight 2" />
            <category term="Silverlight 2 Beta 1" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>So I am just starting to get my feet wet with <a href="http://www.silverlight.net">Silverlight 2</a>.&nbsp; I have gained some <a href="http://mattberseth.com/blog/silverlight_2/">confidence over the past few days</a>, but on the crawl, walk, run scale it feels like I am still crawling.&nbsp; Beginner or not, I figured I would take a shot at getting Silverlight's <a href="http://msdn2.microsoft.com/en-us/library/cc189753(VS.95).aspx">DataGrid</a> control to support sorting.&nbsp; Nothing too complicated - just the standard click on the column header to sort the data.&nbsp; Surprisingly, I didn't see much on MSDN talking about how to implement sorting using the DataGrid.&nbsp; I know the documentation is still in the works so I am sure it is coming, but I was a little bit concerned about how to get started.&nbsp; No worries though, it turned out to be a breeze.&nbsp; If you are interested in the details, I have a quick description of what I did just beneath the following screen shot. </p> <p><a href="http://mattberseth2.com/sl2_datagrid_simple_sort/TestPage.html" target="_blank">Live Demo</a> | <a href="http://mattberseth2.com/downloads/sl2_datagrid_sort.zip" target="_blank">Download</a></p> <p><img height="541" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_f2c9ea73-9273-4251-91aa-c198631bff53.png" width="699"> </p> <h4>Creating Some Data</h4> <p>If you follow my blog, you may have noticed that I am partial to the Northwind data set.&nbsp; This example is no different - my grid is filled with the rows from the customers table.&nbsp; And I cheated a bit and hard-coded my data so I could focus on the sorting interface and not worry about fetching them from the database.&nbsp; I figure I can work on the web service part later.</p> <p>I added a Customer class to my application that contains a handful of the attributes defined by the customer table.&nbsp; Then I added a static Get method to the Customer class that loads the Customer list if it hasn't been loaded already and returns it.&nbsp; It looks something like this ...</p> <p><img height="745" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_7cc99ea3-04d9-49d4-a834-368f47b134d7.png" width="563"> </p> <p>And just as a side note, I didn't actually key in all 91 Add statements.&nbsp; I used a bit of SQL to generate these based on the rows in the customer table.&nbsp; If you give a lot of presentations, demos or just need to create some test data - don't forget about SQL Server.&nbsp; It can be very handy as a crude code generation tool when you need something quick.&nbsp; </p> <p><img height="249" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_3935fd3c-3fb3-4030-85c9-f6e323ae3c80.png" width="443"> </p> <h4>Defining the DataGrid's Columns </h4> <p>Like ASP.NET 2.0's GridView, the Silverlight DataGrid can infer what column's need to be displayed based on the properties that are found on the data source.&nbsp; The <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.datagrid.autogeneratecolumns(VS.95).aspx">AutoGenerateColumns</a> property is what controls this behavior.&nbsp; When it is set to true, the DataGrid automatically adds the columns when the ItemSource property is set.&nbsp; To be honest though, when working with the GridView I usually don't set the AutoGenerateColumns property to true.&nbsp; I always want to control the order of the columns, the name (Company Name instead of CompanyName) and often times I do not want to show all of the properties my data source makes available.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p> <p>To get this type of behavior, you can use the DataGrid's <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.datagrid.columns(VS.95).aspx">Columns</a> collection to define the order, header text and type for each of the columns you want displayed.&nbsp; Like the GridView, you can create different type of column elements based on the data type you are binding to the column to.&nbsp; Right now it looks like the DataGrid has a <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.datagridtextboxcolumn(VS.95).aspx">DataGridTextBoxColumn</a> for text content, a <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.datagridcheckboxcolumn(VS.95).aspx">DataGridCheckBoxColumn</a> for tri-state (Yes/No/Unknown) content and of course a very flexible <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.datagridtemplatecolumn(VS.95).aspx">DataGridTemplateColumn</a> that supports templating.&nbsp; </p> <p>Below is a sample where I am explicitly defining the contents of the Columns property using the markup.</p> <p><img height="337" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_8bf506f9-99c3-43cc-83d9-e41ebb39873a.png" width="676"> </p> <h4>Adding HyperlinkButton's for the Column Header</h4> <p>If you notice in the above screen shot, I have specified each column's header text using the DataGridTextBoxColumn.Header attribute.&nbsp; Well it turns out the XAML programming model is pretty darn flexible.&nbsp; And I could have used the property element syntax to specify the header title by setting the Header property to a TextBlock like so ...</p> <p><img height="113" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_7a7e4513-8489-4d46-9b2f-1a9c19500b96.png" width="546"> </p> <p>And if I replace the TextBlock control with a <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.hyperlinkbutton(VS.95).aspx">HyperlinkButton</a> (which exposes a Click event) things start coming together for my sorting scenario.&nbsp; Now the XAML for the Customer's ID DataGridTextBoxColumn takes on the following form.&nbsp; Notice I have attached an event handler to the Click event and assigned the Tag attribute to the property I want to sort by.</p> <p><img height="200" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_2ca69c21-88f6-4fcb-995c-cc3dc1174703.png" width="543"> </p> <p>And because I am using the Tag attribute to let me know what property to sort by I can attach all of the column header Click events to the same event handler.&nbsp; Giving use something like this.</p> <p><img height="822" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_81913c99-8a46-44b9-8028-cb05d867ebf7.png" width="658"> </p> <h4>Implementing the Click Event Handler</h4>And now for the easy part.&nbsp; Our Sort_Click event handler will determine what property to sort the Customers collection by from looking at the value of the Tag attribute.&nbsp; So I have setup a switch statement that orders the in-memory Customers list by the property that corresponds to the column header that was clicked.&nbsp; One thing to note is that because the DataGrid control doesn't maintain the sort state, I have to keep track of the last sort property and direction to determine how to order the collection (ASC or DESC) if the same header is clicked twice.&nbsp;&nbsp;&nbsp; <p><img height="441" alt="image" src="http://mattberseth.com/WindowsLiveWriter/edce838b6c44_1003B/image_a41cd92a-2be5-4260-be94-1e9da1a21bc1.png" width="721"> </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>A Quick Look at Silverlight 2&apos;s DataGrid Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/03/a_quick_look_at_silverlight_2s.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=111" title="A Quick Look at Silverlight 2's DataGrid Control" />
    <id>tag:mattberseth.com,2008://1.111</id>
    
    <published>2008-03-24T00:20:23Z</published>
    <updated>2008-03-24T00:20:54Z</updated>
    
    <summary><![CDATA[If you follow my blog, you have probably noticed my obsession with data grids.&nbsp; I haven't actually checked my archives, but if I had to guess I would bet somewhere around 70% of all my posts in some way include ASP.NET's Repeater, GridView or ListView controls.&nbsp; Lately I have been taking a look at Silverlight 2 so naturally I was curious when I saw Scott Morrision's post titled Using the Silverlight DataGrid.&nbsp; I eagerly read through his post and started working on creating a very basic demo app.&nbsp; I thought a good way to introduce myself to the DataGrid would be to build a page that allows me to set the values of the DataGrid properties so I could watch how it effects how the DataGrid presentation (usually this is what a designer is for, but it wasn't working so well for me.&nbsp; I am sure it's user error.).&nbsp; Anyway,...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="Prototype" />
            <category term="Silverlight 2" />
            <category term="Silverlight 2 Beta 1" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>If you follow my <a href="http://mattberseth.com">blog</a>, you have probably noticed my obsession with data grids.&nbsp; I haven't actually checked my <a href="http://mattberseth.com/archives.html">archives</a>, but if I had to guess I would bet somewhere around 70% of all my posts in some way include ASP.NET's <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.aspx">Repeater</a>, <a href="http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview(VS.80).aspx">GridView</a> or <a href="http://msdn2.microsoft.com/en-us/library/bb398790.aspx">ListView</a> controls.&nbsp; Lately I have been taking a look at <a href="http://silverlight.net">Silverlight 2</a> so naturally I was curious when I saw <a href="http://blogs.msdn.com/scmorris/default.aspx">Scott Morrision's</a> post titled <a href="http://blogs.msdn.com/scmorris/archive/2008/03/21/using-the-silverlight-datagrid.aspx">Using the Silverlight DataGrid</a>.&nbsp; </p> <p>I eagerly read through his post and started working on creating a very basic demo app.&nbsp; I thought a good way to introduce myself to the DataGrid would be to build a page that allows me to set the values of the DataGrid properties so I could watch how it effects how the DataGrid presentation (usually this is what a designer is for, but it wasn't working so well for me.&nbsp; I am sure it's user error.).&nbsp; Anyway, I found this little app useful so I figured I would post the demo and source.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p> <p>Also, just in case you haven't seen - the Silverlight DataGrid supports column resizing and freezing column/row headers!&nbsp; If you play around with the demo page you can see how this looks.&nbsp; </p> <p><a href="http://mattberseth2.com/silverlight_datagrid_intro/testpage.html" target="_blank">Live Demo</a> | <a href="http://mattberseth2.com/downloads/silverlight_datagrid_intro.zip">Download</a></p> <p><img height="670" alt="image" src="http://mattberseth.com/WindowsLiveWriter/531aae506233_10880/image_89d6635d-d4a3-405a-a416-9662e6cf830d.png" width="694"> </p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Creating a Custom Skin for Silverlight 2&apos;s Button Control</title>
    <link rel="alternate" type="text/html" href="http://mattberseth.com/blog/2008/03/creating_a_custom_skin_for_sil.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://mattberseth.com/blog-mt/mt-atom.cgi/weblog/blog_id=1/entry_id=110" title="Creating a Custom Skin for Silverlight 2's Button Control" />
    <id>tag:mattberseth.com,2008://1.110</id>
    
    <published>2008-03-19T03:07:48Z</published>
    <updated>2008-03-19T03:08:07Z</updated>
    
    <summary><![CDATA[For the past couple of weeks I have been reading about Silverlight 2.&nbsp; I have gone through ScottGu's tutorial, checked out the deep zoom demos (here and here) and even browsed the XAML for some sample control themes.&nbsp; But I haven't actually tried to build anything myself yet.&nbsp; So I thought I would put together a small sample around Silverlight's styling and templating features by creating a skin for the Button control that looks somewhat like the a button renders in IE7 on my Vista box.&nbsp; I know that in a way it's taking a step back (Silverlight's default Button is really pretty sweet looking), but I didn't want to be too overwhelmed for my first sample.&nbsp; The grid below shows what my Button control looks in each of the 4 states the Button supports.&nbsp; If you look close at the Buttons background, you can see it has that nice...]]></summary>
    <author>
        <name>matt@mattberseth.com</name>
        
    </author>
            <category term="Prototype" />
            <category term="Silverlight 2" />
            <category term="Silverlight 2 Beta 1" />
    
    <content type="html" xml:lang="en" xml:base="http://mattberseth.com/">
        <![CDATA[<p>For the past couple of weeks I have been reading about <a href="http://silverlight.net">Silverlight 2</a>.&nbsp; I have gone through <a href="http://weblogs.asp.net/scottgu/">ScottGu's</a> <a href="http://weblogs.asp.net/scottgu/archive/2008/02/22/first-look-at-silverlight-2.aspx">tutorial</a>, checked out the <a href="http://labs.live.com/Silverlight+2+Deep+Zoom.aspx">deep zoom</a> demos (<a href="http://memorabilia.hardrock.com/">here</a> and <a href="http://joestegman.members.winisp.net/DeepZoom/">here</a>) and even browsed the XAML for <a href="http://blogs.msdn.com/brada/archive/2008/03/12/great-new-silverlight-control-skins.aspx">some sample control themes</a>.&nbsp; But I haven't actually tried to build anything myself yet.&nbsp; So I thought I would put together a small sample around <a href="http://msdn2.microsoft.com/en-us/library/cc189093(vs.95).aspx">Silverlight's styling and templating features</a> by creating a skin for the <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.button(VS.95).aspx">Button</a> control that looks somewhat like the a button renders in IE7 on my Vista box.&nbsp; I know that in a way it's taking a step back (Silverlight's default Button is really pretty sweet looking), but I didn't want to be too overwhelmed for my first sample.&nbsp; </p> <p>The grid below shows what my Button control looks in each of the 4 states the Button supports.&nbsp; If you look close at the Buttons background, you can see it has that nice glassy look that we used to use images for when working with HTML.&nbsp; Besides that bit of flare, the rest of the Button is primarily made up of one of the most basic Silverlight elements - the <a href="http://msdn2.microsoft.com/en-us/library/system.windows.shapes.rectangle.aspx">Rectangle</a> (one for the background, one for the glassy overlay and another for the focus dashed border).&nbsp; In addition to the Rectangles, my custom Button skin is also configured to animate the Button as the user mouses over, clicks or disables the Button.&nbsp; Below are some screen shots of what my custom Button looks like in a few different states.</p> <p><img height="139" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_61b96c82-3248-459c-83e8-a0c6b73cf6b2.png" width="436"></p> <p><a href="http://mattberseth2.com/silverlight_button_skin/testpage.html" target="_blank">Live Demo</a> | <a href="http://mattberseth2.com/downloads/silverlight_button_skins.zip" target="_blank">Download (Requires VS 2008 Plus Silverlight 2 Beta 1 Tools)</a> </p> <p>&nbsp;</p> <h4>Customizing the Button's Control's Appearance</h4> <p>Before we can start skinning the Button control, we need to understand what the Button's visual customization points are - this way we can tap into them to control how it renders.&nbsp; </p> <h5><strong>Using in-lined styles</strong></h5> <p>Much like ASP.NET controls, the Buttons appearance can be customized by setting the buttons attributes via the markup.&nbsp; So if you want a blue button, just set the Background attribute to the value Blue.&nbsp; </p> <p><img height="52" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_fbeec776-5d21-4d8a-9d50-091f66d54beb.png" width="634"> </p> <p><img height="61" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_7ce37c08-0c29-4080-88fe-837f8bd0fdb3.png" width="185"> </p> <h5><strong>Using style elements</strong> </h5> <p>That should feel pretty natural for most UI developers.&nbsp; But of course in-lining styles is hard to maintain and gets messy pretty fast.&nbsp; So instead we could move these inline settings to the Resources collection of the Application to encapsulate these settings as a reusable resource - ala CSS.&nbsp; To do this, I have added a Style element to the Application's nodes Resources collection.&nbsp; Within this Style element, I have set the Background property to Blue as follows ...</p> <p>App.xaml</p> <p><img height="200" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_fa08fa19-b29d-453e-af11-a4387c7b7d3a.png" width="572"> </p> <p>Page.xaml</p> <p><img height="44" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_49706ea1-48ac-48c5-b23f-bf075c5659c7.png" width="752"> </p> <p><img height="60" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_803e3d04-80b5-4967-9235-b611c6585de1.png" width="184"> </p> <p>Again, this pattern should feel pretty familiar if you are comfortable with CSS.&nbsp; Instead of in-lining styles, you just point to the resource that knows what style elements you want applied.</p> <h5><strong>Completely replacing a control's visual appearance while still keeping the original behavior</strong></h5> <p>And now to the really cool part.&nbsp; With Silverlight and WPF we can customize just about every aspect of how the Button control renders.&nbsp; ScottGu's tutorial on using <a href="http://weblogs.asp.net/scottgu/pages/silverlight-tutorial-part-7-using-control-templates-to-customize-a-control-s-look-and-feel.aspx">control templates</a> has some pretty interesting examples that show the full flexibility of this technique by embedding a fully functional calendar control within the Buttons content (the screen shot below is from his blog).&nbsp;&nbsp;&nbsp; </p> <p><img height="300" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_e31a1109-ce76-47af-b518-1c526a559175.png" width="475"> </p> <p>And along with allowing us to add other shapes and controls to the Button's template, the Button control also supports hooks that allows us to declaratively specify how our button should look as it as it passes through the following four states: {<strong>Normal State</strong>, <strong>MouseOver State</strong>, <strong>Pressed State</strong>, <strong>Disabled State</strong>} as well as when the button currently has focus.&nbsp; I found the following description from MSDN especially helpful in explaining this.&nbsp; </p> <blockquote> <p><em>When you create a new template for a control, you redefine its visual structure and visual behavior. Is some cases, the code of a control might refer to parts of the control's </em><a href="http://msdn2.microsoft.com/en-us/library/ms609827(VS.95).aspx"><em>ControlTemplate</em></a><em>. For example, the code might call a method on an element that is in the template to perform some functionality. This means you must <strong>understand how the template and the code relate to each other</strong>. That relationship is described by the control contract, which is an agreement between the logical and visual parts of the control. - <a href="http://msdn2.microsoft.com/en-us/library/cc189093(vs.95).aspx">MSDN</a></em></p></blockquote> <p>And I think I get this - the code for the control needs to know a little something about the items in the template for it to function properly.&nbsp; If you want the background color to change from red to blue when the button is hovered over, you need to let the Button know.&nbsp; Or when my control currently has focus, the Button can make sure the dashed rectangle shape is displayed.&nbsp; So after learning about these additional customization points I went to the Button control's&nbsp; <a href="http://msdn2.microsoft.com/en-us/library/cc278069(vs.95).aspx">Style and Templates page on MSDN</a> where I found a description of the elements and <a href="http://msdn2.microsoft.com/en-us/library/system.windows.media.animation.storyboard.aspx">StoryBoard</a> (used for playing animations) the Button control looks for within the ControlTemplate.&nbsp; So if you are creating a template for the Button and want a certain animation played when the Button is hovered over - make sure you include a StoryBoard item within the template with the name <strong>MouseOver State</strong>.&nbsp; Below is a table that summarizes these additional elements that make up the Button controls public interface.</p> <p><img height="371" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_d47e5ba4-bb44-4a83-9a98-4660eadf681a.png" width="670"> </p> <p>These additional bits of information are call Template Parts in the documentation.&nbsp; And if you go to the <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.button(VS.95).aspx">MSDN page</a> for the Button control, you will notice these items are specified as part of the documentation for the Button class.&nbsp; I don't think you would get to far creating a control skin if you don't understand what Template Parts a control defines.</p> <p><img height="176" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_08272809-a476-40b9-b6d5-142958155f08.png" width="607"> </p> <p>&nbsp;</p> <h4>Creating the Shapes that Define the IE Button Skin</h4> <p>And now with some of the background information out of the way, we can start creating our IE button skin.&nbsp;&nbsp; </p> <p><strong><u>Step 1: Add the RootElement, background Rectangle and the ContentPresenter</u></strong></p> <p>If we look back to the table above, the Button's ControlTemplate looks for two elements within the control's template: one with the name <strong>RootElement </strong>and the other with the name <strong>FocusVisualElement</strong>.&nbsp; The RootElement is the element that contains all of the visual elements for our control - so this is where we will start.&nbsp; I have used the Grid control for the layout of my Button and the first child contained within the Grid is a Rectangle (with rounded corners natively supported!) that is filled with a light gray color.&nbsp; After the Rectangle I have added a <a href="http://msdn2.microsoft.com/en-us/library/system.windows.controls.contentpresenter.aspx">ContentPresenter</a> that handles rendering the content portion of the Button.&nbsp; I have used markup extension syntax to bind the properties of the control to the ContentPresenter (I am still wrapping my head around exactly what a ContentPresenter is and isn't.&nbsp; When I figure that out well enough so that I can explain it I will no doubt include a post about it).&nbsp; </p> <p><img height="622" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_57c1bfe3-e8dd-4968-bddc-12307baed655.png" width="759">&nbsp;&nbsp; </p> <p>With just this single rectangle, the button displays like this:</p> <p><img height="62" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_d81d3eed-f1ec-4cc4-a7bb-ad143556edc1.png" width="112">&nbsp;</p> <p><strong><u>Step 2: Add the glassy-look by overlaying a semi-transparent Rectangle</u></strong></p> <p>Next, I added another Rectangle to the template that sits on top of the Background Rectangle.&nbsp; This second Rectangle is responsible for providing us with the nice glassy effect.&nbsp; To achieve this I added a second Rectangle to the markup (unless I am mistaken, Z-Order is the order in which the items are added.&nbsp; Because the Background Rectangle is added first it will have a lower Z-Order).&nbsp; And instead of adding a semi-transparent image, instead I filled this rectangle with a gradient brush - lighter on the top, darker on the bottom. </p> <p><img height="369" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_ce2b6ac7-dd59-450d-af7b-741601d599ff.png" width="554"> </p> <p>With the second Rectangle added to the template, the button now displays like this:</p> <p><img height="61" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_edd64c92-b976-4788-a91c-be2d19409839.png" width="108">&nbsp; </p> <p><strong><u>Step 3: Add the FocusVisualElement Rectangle</u></strong></p> <p>Next, I added another Rectangle to the template that handles applying the dashed shape just inside the Buttons border when the button currently has focus.&nbsp; Again, I added this Rectangle after the first two so it has the highest z-order.&nbsp; When the button has focus, a white dashed border is applied to the control.&nbsp; <strong>I didn't find this specifically mentioned in the documentation</strong>, <strong>but all of the examples for skinning the button had the FocusVisualElement initially set to the Visibility=Collapsed state</strong>.&nbsp; I haven't verified this, but I believe when the Button determines it has focus it updates the Visibility value to Visible causing the dashed Rectangle to be displayed.&nbsp;&nbsp;&nbsp; </p> <p><img height="183" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_7e766dc0-f03c-4ae6-8e9e-7b619f38209a.png" width="399">&nbsp;</p> <p><strong><u>Step 4: Add a Rectangle that overlays all of the other shapes</u></strong></p> <p>Finally, to handle the disabled button state, I have added yet another Rectangle to the very end of the template (giving it the highest z-order).&nbsp; I initially set the Opacity to 0 making it invisible.&nbsp; When the button enters the <strong>Disabled State </strong>I will use a StoryBoard to update the Opacity value to 1, placing it on top of all of the other Rectangles.</p> <p><img height="181" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_04751bf3-08b2-4c8f-824b-7c32f227366b.png" width="578"> </p> <p><strong><u>Step 5: Use StoryBoards for animating state transitions</u></strong>&nbsp;</p> <p>The last step in building our IE skin is attaching the animations that will be run as the button passes through the 4 well-known button states mentioned earlier.&nbsp; Here is a quick summary of what actions need to be taken as the Button passes through these states:</p> <table cellspacing="0" cellpadding="2" width="678" border="1"> <tbody> <tr> <td align="middle" width="150"><strong>MouseOver State</strong></td> <td width="308"> <ul> <li>Change the color of the Background Rectangle to Blue</li></ul></td> <td align="middle" width="218"><img height="60" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_e4335a92-e7dc-4235-9105-b9a00e2c647f.png" width="110"></td></tr> <tr> <td align="middle" width="153"><strong>Pressed State</strong></td> <td width="307"> <ul> <li>Change the Background Rectangle to Blue  <li>Make the gradient Rectangle slightly see through by setting the Opacity to 0.7 (this will make more of the Blue color show through)  <li>Thicken up the border</li></ul></td> <td align="middle" width="218"><img height="61" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_295a51b5-9610-445c-83af-aa865eea85ab.png" width="110"></td></tr> <tr> <td align="middle" width="155"><strong>Normal State</strong></td> <td width="306"> <ul> <li>Make the Background Gray,&nbsp; </li></ul></td> <td align="middle" width="218"><img height="60" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_800b1ad8-94cc-41f9-a379-f08c4d653af4.png" width="109"></td></tr> <tr> <td align="middle" width="156"><strong>Disabled State</strong></td> <td width="305"> <ul> <li>Render a grayed out Rectangle over the control</li></ul></td> <td align="middle" width="218"><img height="64" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_8c1626c8-bf25-4dac-92a4-23a9da07f7c7.png" width="110"> </td></tr></tbody></table> <p>&nbsp;</p> <p>If you notice, when the button changes between the various states, I want to update properties on a few of the embedded Rectangles.&nbsp; To achieve this, I have added 4 StoryBoard nodes to my template - a different StoryBoard for each of the Button states.&nbsp; The MouseOver StoryBoard is the simplest one - it runs when the user mouses over the RootElement.&nbsp; This StoryBoard uses the ColorAnimation object to change the Color property of the Brush that fills the Background Rectangle from gray to blue.&nbsp; Here is the markup for this StoryBoard ...</p> <p><img height="234" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_18fea448-53a0-43b1-b321-d710ffc06b0b.png" width="454"> </p> <p>A few things to notice:</p> <ul> <li>The value of the StoryBoard's Key attribute is <strong>MouseOver State</strong>.&nbsp; The Button control looks for this item by name, so you will need to enter it just as I have above  <li>The Duration of my animation is set to 0:0:0 - meaning this animation happens instantly.&nbsp; If you wanted it to slowly turn blue, you could set this to a small value.&nbsp; Something like 0:0:0.5 would cause it to turn to from gray to blue in 1/2 a second.  <li>The ColorAnimation is pointing to the Target named <strong>Brush.&nbsp; </strong>If you look back to step 1, this is the name of the Brush that fills the Background Rectangle</li></ul> <p>The rest of the animations follow a similar pattern.&nbsp; The TargetName attribute points to the item I want to animate.&nbsp; And I animate the objects by changing one of their property values (i.e. Opacity, StrokeThickness, Color).&nbsp; </p> <p>And finally, after all of this work is done, I have moved my new skin to the Resources section of the Application XAML file and used the Style setting to point my buttons towards their lovely new IE skin ...</p> <p><img height="334" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_95357273-0b2c-4f04-ab22-ad1d2f17ed90.png" width="495"> </p> <p>And when all of this runs - it looks something like this.</p> <p><img height="103" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_3d164c78-85c3-495b-b933-eb45e420185d.png" width="122"> </p> <p>Finally, I collapsed all of the elements and resources that make up my custom style so you could get a feel for what it looks like when it is all put together.&nbsp; The complete skin comes to a about 150 lines of markup.&nbsp; Really not too bad considering the flexibility it provides.&nbsp; I haven't worked with Silverlight too long, but I am already getting the feeling that control skinning is going to be one of my favorite topics.</p> <p><img height="729" alt="image" src="http://mattberseth.com/WindowsLiveWriter/2059fa9bb004_11DB6/image_24b86bce-72a2-4c1c-bdcf-648b7715aad3.png" width="525">&nbsp;</p> <p>That's it.&nbsp; Enjoy!</p>]]>
        
    </content>
</entry>
<entry