<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6181362549951896980</id><updated>2011-11-27T16:39:01.853-08:00</updated><category term='Introduction'/><category term='LINQ'/><category term='Visual Studio 2008 SP 1'/><category term='.Net 4.0'/><category term='Microsoft'/><category term='SQL'/><category term='extender design pattern'/><category term='toastmasters'/><category term='Test Driven Development'/><category term='web user controls'/><category term='Rich Internet Applications'/><category term='CodeProject'/><category term='AJAX'/><category term='Colorado'/><category term='ADO.Net Entitiy Framework'/><category term='RIA'/><category term='computers'/><category term='web applicaitons'/><category term='Visual Studio 2010'/><category term='volleyball'/><category term='custom web user interface'/><category term='ASP.NET AJAX'/><category term='Task List'/><category term='LINQ to Entities'/><category term='TDD'/><category term='web applicatons'/><category term='extenders'/><category term='reusable subassemblies'/><category term='Test Driver Design'/><category term='Software'/><category term='Software Development Methods'/><category term='health'/><category term='AJAX Control Toolkit'/><title type='text'>Ray Wampler's .Net Programming Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-4757923219956163325</id><published>2010-11-25T23:44:00.000-08:00</published><updated>2010-11-25T23:44:22.118-08:00</updated><title type='text'>When to use Entity Sql vs LINQ to Entities</title><content type='html'>Microsoft now has so many different data access technologies, how do you choose?  ADO.Net served us well for many years, and then Microsoft introduced LINQ - Language INtegrated Query.  Dot-Net 2.0 offered LINQ to SQL.  With .Net 3.5 and 4.0 we have the Entity framework and LINQ to Entities.&lt;br /&gt;
&lt;br /&gt;
In addition there is also &lt;a href="http://raywampler.blogspot.com/2010/03/introduction-to-entity-sql.html"&gt;Entity SQL&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
When would you use this?  My take on it is that if you already know which &lt;a href="http://msdn.microsoft.com/en-us/data/ff191186.aspx"&gt;Entity Model&lt;/a&gt; you're using at the time you're writing the code then LINQ to Entities is easier because you can take full advantage of intellisense.  If you want to do more abstract coding that will work on any model then Entity SQL will allow you to write the SQL statement dynamically at run time.&lt;br /&gt;
&lt;br /&gt;
For example, with LINQ to Entities you can do this:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;NorthwindEntities context = new NorthwindEntities();&lt;br /&gt;
            IQueryable&amp;lt;Product&amp;gt; qry = from p in context.Products&lt;br /&gt;
                      where p.UnitsInStock &amp;lt; p.ReorderLevel&lt;br /&gt;
                      select p;&lt;br /&gt;
&lt;/blockquote&gt;In the above example when you type "IQueryable&amp;lt;", "context.", and "p." you get intellisense that helps you select the right entity and field names.&lt;br /&gt;
&lt;br /&gt;
So when you know ahead of time that you want to get data from a specific table in a specific model then LINQ to Entities is easier.  &lt;br /&gt;
&lt;br /&gt;
Let's say that you want to do something more generic.  For example, let's say you want to select the maximum value from some column of some unknown type in some table.  You can do it with Entity SQL like this:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;public T MaxValue&amp;lt;T&amp;gt;(ObjectContext context, MetaColumn pkCol)&lt;br /&gt;
        {&lt;br /&gt;
            string maxQuery = "SELECT Max(p." + pkCol.Name +&lt;br /&gt;
                ") FROM " + pkCol.Table.Name + " as p";&lt;br /&gt;
&lt;br /&gt;
            ObjectQuery&amp;lt;DbDataRecord&amp;gt; query =&lt;br /&gt;
                new ObjectQuery&amp;lt;DbDataRecord&amp;gt;(maxQuery, context);&lt;br /&gt;
&lt;br /&gt;
            DbDataRecord rec = query.First();&lt;br /&gt;
            return (T)rec[0];&lt;br /&gt;
        }&lt;br /&gt;
&lt;/blockquote&gt;We use generics to specify the type, T, of the result, which could be an int or a double, or a string, or any type that would work with the Max function.  We're given an ObjectContext and the MetaColumn for which we want to find the max.&lt;br /&gt;
&lt;br /&gt;
Let's say that the MetaColumn is the Id column in the Products table.  The Entity SQL would end up being:&lt;br /&gt;
&lt;br /&gt;
 &lt;blockquote&gt;SELECT Max(p.Id) FROM Product as p&lt;/blockquote&gt;&lt;br /&gt;
But it would work with any column of any type in any table.  The ObjectQuery&lt;DbDataRecord&gt; gives you a generic collection of generic columns which use can cast to the type that you need using generics.&lt;br /&gt;
&lt;br /&gt;
So when the query is fully known at compile time then LING to Entities is easier, but when you need to construct a query at run time then Entity SQL gives you that flexibility.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-4757923219956163325?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/4757923219956163325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=4757923219956163325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/4757923219956163325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/4757923219956163325'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2010/11/when-to-use-entity-sql-vs-linq-to.html' title='When to use Entity Sql vs LINQ to Entities'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-2478548469804728191</id><published>2010-03-11T21:31:00.000-08:00</published><updated>2010-03-14T15:11:26.607-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.Net 4.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2010'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.Net Entitiy Framework'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ to Entities'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Introduction to Entity Sql</title><content type='html'>&lt;p&gt;The ADO.Net Entity Framework is the latest evolution in data access from Microsoft, making ORM (object relational mapping) part of the .Net Framework. As I learn the basic of this new technology I thought I'd take you along for the ride.&lt;/p&gt;

&lt;p&gt;There are two methods for querying an entity model within your code, Entity SQL (eSql) and LINQ to Entities. The latter is an extension of LINQ (Language INtegrated Query), Microsoft's general-purpose object query syntax that is built into .Net languages C# and VB. There are several varieties of LINQ: LINQ to SQL, LINQ to Entities, LINQ to XML, etc. You can create your own extensions to LINQ if have a specialized set of objects you wish to query.&lt;/p&gt;

&lt;p&gt;Entity SQL uses a syntax that is similar to SQL and returns a generic collection, ObjectQuery&amp;gt;T&amp;lt;.&lt;/p&gt;

&lt;p&gt;The basic syntax for an eSql query is:&lt;/p&gt;

&lt;p&gt;SELECT Entity.property FROM Entity&lt;/p&gt;

&lt;p&gt;It is similar to transact-Sql except all column or property names must qualified in select clause. You use aliases in the FROM clause to save typing:&lt;/p&gt;

&lt;p&gt;SELECT e.property FROM Entity AS e&lt;/p&gt;

&lt;p&gt;If you were querying from an entity model of the Northwinds database this would be a valid query:&lt;/p&gt;

&lt;p&gt;SELECT v.AccountNumber, v.Name FROM Vendors AS v&lt;/p&gt;

&lt;p&gt;One thing to remember is that entity collections are plural. So eventhough the underlying Sql Server table is Vendor, singular, the entity collection is Vendors, plural.&lt;/p&gt;

&lt;p&gt;Where do you use this Sql statement? You create an object query, which can either be of an entity type or use the generic dbDataRecord. The constructor of the ObjectQuery takes two arguments:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The Entity Sql&lt;/li&gt;&lt;li&gt;An Entity Context&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;AdventureWorksEntities advEnt = new AdventureWorksEntities();&lt;br /&gt;
String sql = "SELECT v.AccountNumber, v.Name FROM Vendors AS v";&lt;br /&gt;
&lt;br /&gt;
ObjectQuery&lt;dbdatarecord&gt; query = new ObjectQuery&lt;dbdatarecord&gt;(sql, advEnt);
&lt;/p&gt;

&lt;p&gt;The above code will return a collection of that you can index just like an array:&lt;/p&gt;

&lt;p&gt;
foreach (DbDataRecord rec in query)&lt;br /&gt;
{&lt;br /&gt;
Console.WriteLine("{0}\t{1}", rec[0], rec[1]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;That gets us started with Entity Sql. In future posts I'll many of the other features of this new data access method.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-2478548469804728191?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/2478548469804728191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=2478548469804728191' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2478548469804728191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2478548469804728191'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2010/03/introduction-to-entity-sql.html' title='Introduction to Entity Sql'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-6307143523079867328</id><published>2009-01-06T15:08:00.000-08:00</published><updated>2009-01-07T13:54:46.140-08:00</updated><title type='text'>Using Web User Controls to Create Rich Internet Application Subassembies - Part 2</title><content type='html'>&lt;p class="MsoNormal"&gt;In my &lt;a href="http://raywampler.blogspot.com/2008/10/using-web-user-controls-to-create-rich.html"&gt;previous blog entry &lt;/a&gt;I gave an overview of the advantages of using ASP.Net web user controls to create generic, reusable
subassemblies that can form the basis of your own library of web application
building blocks. In this post I will walk you step-by-step through a real
world example.&lt;/p&gt;&lt;h2 class="Section1"&gt;Creating our Visual Studio Project&lt;/h2&gt;&lt;p class="MsoNormal"&gt;To follow along, first make sure you have the AJAX Control Toolkit installed for your version of Visual Studio. If you’re using Visual Studio 2008 then go to the &lt;a href="http://www.codeplex.com/AjaxControlToolkit"&gt;ASP.Net AJAX CodePlex site&lt;/a&gt; to download the latest version. If you’re still using Visual Studio 2005 then you’ll need to create a new &lt;b&gt;AJAX Control Toolkit Website&lt;/b&gt;, which should appear under My Templates after you have installed the &lt;a href="http://www.asp.net/ajax/downloads/archive/"&gt;AJAX Control Toolkit for ASP.NET 2.0&lt;/a&gt;.&lt;/p&gt;&lt;p class="MsoNormal"&gt;After you get the toolkit then you need to add it to the Visual Studio toolbox so that you can drop and drop the components into your web page using the designer. MBrock.com has a &lt;a href="http://www.mbrock.com/work/asp-net/34-aspnet/44-installing-the-ajax-control-toolkit-in-visual-studio-2008"&gt;helpful blog entry&lt;/a&gt; that walks you through the process.
&lt;/p&gt;&lt;p class="MsoNormal"&gt;Open Visual Studio 2008 and create a net &lt;b&gt;ASP.NET Web Site&lt;/b&gt;
named AJAXsubassemblyExample. Lets keep our web user controls separate from
the other parts of the site by creating a folder for them called “UIControls.” &lt;/p&gt;&lt;h2 class="Section1"&gt;Building the Web User Control&lt;/h2&gt;&lt;p class="MsoNormal"&gt;Right-click the UIControls folder and select Add New Item.
Select Web User Control and name it NumericData.&lt;/p&gt;&lt;p class="MsoNormal"&gt;The first item we’ll add will to the web user control will
be text box. Drag a textbox from the Standard tab and change the ID to &lt;span style="font-family:'Courier New';color:blue;"&gt;txtNumericData.&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Next, add a Masked Edit Extender. Set &lt;span style="font-family:'Courier New';color:red;"&gt;TargetControlID&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="txtNumericData"&lt;/span&gt;,
&lt;span style="font-family:'Courier New';color:red;"&gt;MaskType&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="Number"&lt;/span&gt; and &lt;span style="font-family:'Courier New';color:red;"&gt;Mask&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="999999999999"&lt;/span&gt;. &lt;/p&gt;&lt;p class="MsoNormal"&gt;12 digits will be our default; later we’ll add some properties for minimum and maximum values and then programmatically adjust the mask to match the property settings.&lt;/p&gt;&lt;p class="MsoNormal"&gt;We want to support a public property named, “IsRequired” that can control whether our numeric data subassembly will be a required field on the page. Add a RequiredFieldValidator from under the Validation tab, make &lt;span style="font-family:'Courier New';color:red;"&gt;ControlToValidate&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="txtNumericData"&lt;/span&gt;
and &lt;span style="font-family:'Courier New';color:red;"&gt;Enabled&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="false"&lt;/span&gt;.

This makes the field not required by default. We’ll add a property later that will allow the user to set this.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Finally, we’ll add a RangeValidator, again setting &lt;span style="font-family:'Courier New';color:red;"&gt;ControlToValidate&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="txtNumericData"&lt;/span&gt;
and &lt;span style="font-family:'Courier New';color:red;"&gt;Enabled&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;="false"&lt;/span&gt;.
The source for UIControls/NumericData.ascx will look like this:&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="BACKGROUND: yellow;font-family:'Courier New';" &gt;&amp;lt;%&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;@&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:#a31515;"&gt;Control&lt;/span&gt;
&lt;span style="color:red;"&gt;Language&lt;/span&gt;&lt;span style="color:blue;"&gt;="C#"&lt;/span&gt;
&lt;span style="color:red;"&gt;AutoEventWireup&lt;/span&gt;&lt;span style="color:blue;"&gt;="true"&lt;/span&gt;
&lt;span style="color:red;"&gt;CodeFile&lt;/span&gt;&lt;span style="color:blue;"&gt;="NumericData.ascx.cs"&lt;/span&gt;
&lt;span style="color:red;"&gt;Inherits&lt;/span&gt;&lt;span style="color:blue;"&gt;="UIControls_NumericData"&lt;/span&gt;
&lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="BACKGROUND: yellow;font-family:'Courier New';" &gt;&amp;lt;%&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;@&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:#a31515;"&gt;Register&lt;/span&gt;
&lt;span style="color:red;"&gt;Assembly&lt;/span&gt;&lt;span style="color:blue;"&gt;="AjaxControlToolkit"&lt;/span&gt;
&lt;span style="color:red;"&gt;Namespace&lt;/span&gt;&lt;span style="color:blue;"&gt;="AjaxControlToolkit"&lt;/span&gt;
&lt;span style="color:red;"&gt;TagPrefix&lt;/span&gt;&lt;span style="color:blue;"&gt;="cc1"&lt;/span&gt;
&lt;span style="BACKGROUND: yellow"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;TextBox&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;="txtNumericData"&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;="server"&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;TextBox&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;cc1&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;MaskedEditExtender&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;="MaskedEditExtender1"&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;="server"&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;TargetControlID&lt;/span&gt;&lt;span style="color:blue;"&gt;="txtNumericData"&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;MaskType&lt;/span&gt;&lt;span style="color:blue;"&gt;="Number"&lt;/span&gt; &lt;span style="color:red;"&gt;Mask&lt;/span&gt;&lt;span style="color:blue;"&gt;="999999999999"&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;cc1&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;MaskedEditExtender&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;RequiredFieldValidator&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;="RequiredFieldValidator1"&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;="server"&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;ControlToValidate&lt;/span&gt;&lt;span style="color:blue;"&gt;="txtNumericData"&lt;/span&gt; &lt;span style="color:red;"&gt;Enabled&lt;/span&gt;&lt;span style="color:blue;"&gt;="false"&lt;/span&gt; &lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;ErrorMessage&lt;/span&gt;&lt;span style="color:blue;"&gt;="RequiredFieldValidator"&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;RequiredFieldValidator&lt;/span&gt;&lt;span style="color:blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;RangeValidator&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;span style="color:red;"&gt;ID&lt;/span&gt;&lt;span style="color:blue;"&gt;="RangeValidator1"&lt;/span&gt; &lt;span style="color:red;"&gt;runat&lt;/span&gt;&lt;span style="color:blue;"&gt;="server"&lt;/span&gt; &lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;ControlToValidate&lt;/span&gt;&lt;span style="color:blue;"&gt;="txtNumericData"&lt;/span&gt; &lt;span style="color:red;"&gt;Enabled&lt;/span&gt;&lt;span style="color:blue;"&gt;="false"&lt;/span&gt; &lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:red;"&gt;ErrorMessage&lt;/span&gt;&lt;span style="color:blue;"&gt;="RangeValidator"&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;asp&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;:&lt;/span&gt;&lt;span style="font-family:'Courier New';color:#a31515;"&gt;RangeValidator&lt;/span&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;&amp;gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;div class="Section1"&gt;
&lt;/div&gt;&lt;p class="MsoNormal"&gt;We now have all the components for numeric data subassembly
in one neat little package.&lt;/p&gt;&lt;h2 class="Section1"&gt;Defining the Public Properties&lt;/h2&gt;&lt;h3 class="Section1"&gt;Text Box Pass-Through Properties&lt;/h3&gt;&lt;p class="MsoNormal"&gt;The web user control will appear as a “black box” to the web
pages that are using it. The only properties available are those of the
UserControl class and any public properties that we define. Since the text
box, &lt;span style="font-family:'Courier New';color:blue;"&gt;txtNumericData&lt;/span&gt;,
is the main UI element then we should allow users to get and set some of its
properties. We’ll start with a short list and add more as needed:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;div class="MsoNormal"&gt;Height&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal"&gt;Width&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal"&gt;Font and Colors&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal"&gt;Borders&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div class="MsoNormal"&gt;CSS Class&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p class="MsoNormal"&gt;For each property that we want to expose we can define a
public property in the NumericData.ascx.cs code file and tie to the text box’s
property. Here’s how you would define the Height property:
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Unit&lt;/span&gt; Height&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.Height; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.Height = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;There’s really not much code at all; we’re just tying the
property of the web user control directly to the property of the text box. The
property type is &lt;span style="font-family:'Courier New';color:#2b91af;"&gt;Unit&lt;/span&gt;, which is the same data type as the text box Height
property. Any errors that occur when setting the property would get thrown
through to the code that’s doing the setting, so it behaves the same as a
regular text box.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The rest of the properties from our list above are done in
the same way. Fonts, colors, and borders are actually controlled by many
properties so I will spare you the tedium of going through each one and let you
look through the source code below.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;using&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; System.Web.UI.WebControls;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;using&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; System.Drawing;&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal"&gt;...

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;#region&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; TextBox Properties&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Unit&lt;/span&gt; Height&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.Height; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.Height = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Unit&lt;/span&gt; Width&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.Width; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.Width = &lt;span style="color:blue;"&gt;value&lt;/span&gt;;
}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Color&lt;/span&gt; BackColor&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.BackColor; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.BackColor = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Color&lt;/span&gt; BorderColor&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.BorderColor; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.BorderColor = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;BorderStyle&lt;/span&gt; BorderStyle&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.BorderStyle; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.BorderStyle = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Unit&lt;/span&gt; BorderWidth&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.BorderWidth; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.BorderWidth = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt; CssClass&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.CssClass; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.CssClass = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;FontInfo&lt;/span&gt; Font&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.Font; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;CssStyleCollection&lt;/span&gt; Style&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.Style; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:#2b91af;"&gt;Color&lt;/span&gt; ForeColor&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.ForeColor; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.ForeColor = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;int&lt;/span&gt; MaxLength&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
txtNumericData.MaxLength; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { txtNumericData.MaxLength = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;#endregion&lt;/span&gt;&lt;/p&gt;&lt;h3&gt;The Value Property&lt;/h3&gt;&lt;p class="MsoNormal"&gt;I did not add Text to the list of properties because we want
this control to be specialized and handle only numeric data. Therefore we’ll
have a Value property instead which will handle validation and conversion. We
want the control to handle either numeric or integer data so we should make
Value type a double so that it can handle all types of numbers.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Here’s the code for getting the value:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;double&lt;/span&gt; Value&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;try&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;Double&lt;/span&gt;.Parse(txtNumericData.Text); }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;catch&lt;/span&gt; (&lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;
ex)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0; MARGIN-LEFT: 117pt; TEXT-INDENT: -0.25in"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;throw&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt;
&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"Invalid numeric data in control "&lt;/span&gt; + ID,
ex);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;We have a try-catch and inside the try we use the Parse
method of the double type to parse whatever is in the text into a double. If
the Masked Edit Extender is doing its job then this parsing will work. If
something goes wrong we throw the exception, adding a message which will
identify to the programmer the ID of the control that encountered the error.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The set function is similar:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;try&lt;/span&gt; { txtNumericData.Text = &lt;span style="color:blue;"&gt;value&lt;/span&gt;.ToString();
}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;catch&lt;/span&gt; (&lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;
ex)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0; MARGIN-LEFT: 117pt; TEXT-INDENT: -0.25in"&gt;&lt;span style="font-family:'Courier New';color:blue;"&gt;throw&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt;
&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"Invalid numeric data in control "&lt;/span&gt; + ID,
ex);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;Because the property type is double then the try-catch should
never fail because the error checking would happen in the code trying to assign
a value to this property of type double. However, it doesn’t hurt to have the
error handling just in case.&lt;/p&gt;&lt;h3&gt;Value as Int
&lt;/h3&gt;&lt;p class="MsoNormal"&gt;The requirements also specify that we be able to limit the
values entered to integers if the situation calls for it. It would then make sense
to have a property that provides the value as an integer. This becomes a
little complicated because what if you access the integer value when the
control is configured to accept real numbers? We have to choose whether to
truncate, round or throw an exception. Let’s try to be as user-friendly as
possible. The Int.Parse() method will throw an exception if you give it a
string that includes a decimal point. What we can do is start with
Int.Parse(), then try to truncate if that fails:&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;int&lt;/span&gt; ValueInt&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;try&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;int&lt;/span&gt;.Parse(txtNumericData.Text);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;catch&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;return&lt;/span&gt; (&lt;span style="color:blue;"&gt;int&lt;/span&gt;)&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Truncate(Value);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;try&lt;/span&gt; { txtNumericData.Text = &lt;span style="color:blue;"&gt;value&lt;/span&gt;.ToString();
}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;catch&lt;/span&gt; (&lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;
ex)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"Invalid
numeric data in control "&lt;/span&gt; + ID, ex);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;Notice that in the catch of the get we call the Value
property. This lets us reuse the error handling built into the get of that
property. If the text in the numeric text box can be converted to a &lt;span style="font-family:'Courier New';color:blue;"&gt;double&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt; &lt;/span&gt;then the
Math.Truncate method will get the integer portion for us.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The set ends up being the same as that for the Value
property, since the data type of ValueInt is &lt;span style="font-family:'Courier New';color:blue;"&gt;int&lt;/span&gt;, then any errors would occur
in the calling code and we merely need to convert the &lt;span style="font-family:'Courier New';color:blue;"&gt;int&lt;/span&gt; value to a string if we
get this far.&lt;/p&gt;&lt;h3&gt;Is Required Property&lt;/h3&gt;&lt;p class="MsoNormal"&gt;Is Required allows the user to turn the required field
validator on or off. It’s off by default because that’s the way we set it in
the control designer. We can tie the property directly to the Enabled property
of the validator:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;bool&lt;/span&gt; IsRequired&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
RequiredFieldValidator1.Enabled; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt; { RequiredFieldValidator1.Enabled = &lt;span style="color:blue;"&gt;value&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;h3&gt;Range Validation&lt;/h3&gt;&lt;p class="MsoNormal"&gt;We want our numeric data control to support range validation.
We added a Range Validator to our control and can deal with the range validation in a similar way, exposing the minimum and maximum values as properties. One variation that we
can add is changing the type. On a standard range validator the minimum and
maximum values are strings. This is because the validators can be used for numbers,
text, dates, and currency. Since our control is specialized for numbers only
then we can make the minimum and maximum values of type double. Furthermore,
since we want to make the values optional then we will make our property types
nullable doubles:&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;double&lt;/span&gt;? MinimumValue&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.IsNullOrEmpty(RangeValidator1.MinimumValue))&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;null&lt;/span&gt;;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt; &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;double&lt;/span&gt;.Parse(RangeValidator1.MinimumValue);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt;&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (&lt;span style="color:blue;"&gt;value&lt;/span&gt; == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
RangeValidator1.MinimumValue = &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.Empty;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt; RangeValidator1.MinimumValue = &lt;span style="color:blue;"&gt;value&lt;/span&gt;.ToString();&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
SetRangeValidationEnabled();&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;double&lt;/span&gt;? MaximumValu&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (&lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.IsNullOrEmpty(RangeValidator1.MaximumValue))&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;null&lt;/span&gt;;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt; &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;double&lt;/span&gt;.Parse(RangeValidator1.MaximumValue);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (&lt;span style="color:blue;"&gt;value&lt;/span&gt; == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
RangeValidator1.MaximumValue = &lt;span style="color:#2b91af;"&gt;String&lt;/span&gt;.Empty;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt; RangeValidator1.MaximumValue = &lt;span style="color:blue;"&gt;value&lt;/span&gt;.ToString();&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
SetRangeValidationEnabled();&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;private&lt;/span&gt;
&lt;span style="color:blue;"&gt;void&lt;/span&gt; SetRangeValidationEnabled()&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (MinimumValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;
&amp;amp;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;MaximumValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
RequiredFieldValidator1.Enabled = &lt;span style="color:blue;"&gt;false&lt;/span&gt;;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
RequiredFieldValidator1.Enabled = &lt;span style="color:blue;"&gt;true&lt;/span&gt;;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The last feature to add is determining whether the validator
will need to be enabled. If both values are null then we can turn it off.
Since the code is the same for both properties I moved it into a help function &lt;span style="font-family:'Courier New';"&gt;SetRangeValidationEnabled&lt;/span&gt;.&lt;/p&gt;&lt;h3&gt;Number Format Properties&lt;/h3&gt;&lt;p class="MsoNormal"&gt;The next two properties will determine how the number gets
formatted: DecimalPlaces and ShowCommas. These properties will be used when
creating the input mask. The rule for DecimalPlaces is that it can’t be
negative. ShowCommas does not require any special logic so we’ll take
advantage of the new automatic properties feature in C# 3:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;int&lt;/span&gt;
_decimalPlaces = 0;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;int&lt;/span&gt; DecimalPlaces&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt;
_decimalPlaces; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;set&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (&lt;span style="color:blue;"&gt;value&lt;/span&gt; &amp;lt; 0)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;ArgumentOutOfRangeException&lt;/span&gt;(&lt;span style="color:#a31515;"&gt;"decimal places can not be less than 0."&lt;/span&gt;);&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;
_decimalPlaces = &lt;span style="color:blue;"&gt;value&lt;/span&gt;;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt;
&lt;span style="color:blue;"&gt;bool&lt;/span&gt; ShowCommas { &lt;span style="color:blue;"&gt;get&lt;/span&gt;;
&lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;h3&gt;Setting the Mask&lt;/h3&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Now we have enough groundwork done that we can determine the
mask for the masked edit extender. The factors that go into the mask are:
&lt;/p&gt;&lt;ul style="MARGIN-TOP: 0in" type="disc"&gt;&lt;li class="MsoNormal"&gt;Number of decimal places&lt;/li&gt;&lt;li class="MsoNormal"&gt;Show commas&lt;/li&gt;&lt;li class="MsoNormal"&gt;The magnitude of the minimum and maximum values&lt;/li&gt;
&lt;/ul&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;The mask will consist of nines, since this is a numeric
control, combined with commas and the negative sign. The first thing we need
to determine is the number of digits left of the decimal place. For this we
can use the logarithm of the maximum and minimum values, rounding up:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;int&lt;/span&gt; maxNumDigits;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;maxNumDigits = (&lt;span style="color:blue;"&gt;int&lt;/span&gt;)&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Ceiling(&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Log10((&lt;span style="color:blue;"&gt;double&lt;/span&gt;)MaximumValue));&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;
&lt;p class="MsoNormal"&gt;Note that because MaximumValue is a nullable double (&lt;span style="font-family:'Courier New';color:blue;"&gt;double&lt;/span&gt;&lt;span style="font-family:'Courier New';"&gt;?) we need to cast it to a &lt;span style="color:blue;"&gt;double&lt;/span&gt; within the Log10 function. We also should
have code that deals with the null situation and sets the maximum digits to some default number of digits, maybe 18 so that we can handle up to a quadrillion. If we need anything more we just set the maximum value higher. We also have to allow for the possibility that the minimum value could all accept
more digits than the maximum. Here’s what that part of the code would look like:&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;const&lt;/span&gt;
&lt;span style="color:blue;"&gt;int&lt;/span&gt; DEFAULT_MAX_DIGITS = 18&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;private&lt;/span&gt;
&lt;span style="color:blue;"&gt;void&lt;/span&gt; SetMask()&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;int&lt;/span&gt; maxNumDigits;&lt;/span&gt;
&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;if&lt;/span&gt; (MaximumValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;
MinimumValue == &lt;span style="color:blue;"&gt;null&lt;/span&gt;)&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;maxNumDigits =
DEFAULT_MAX_DIGITS;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;&lt;span style="color:blue;"&gt;else&lt;/span&gt;&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;{&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;maxNumDigits = &lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Max((&lt;span style="color:blue;"&gt;int&lt;/span&gt;)&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Ceiling(&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Log10((&lt;span style="color:blue;"&gt;double&lt;/span&gt;)MinimumValue)),&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;(&lt;span style="color:blue;"&gt;int&lt;/span&gt;)&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Ceiling(&lt;span style="color:#2b91af;"&gt;Math&lt;/span&gt;.Log10((&lt;span style="color:blue;"&gt;double&lt;/span&gt;)MinimumValue)));&lt;/span&gt;

&lt;/p&gt;&lt;p class="MsoNormal" style="BACKGROUND: #fcf9d0"&gt;&lt;span style="font-family:'Courier New';"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Testing the Control&lt;/h2&gt;&lt;p class="MsoNormal"&gt;In my next post I will demonstrate how to create a custom web user control test page that will let you play with all the different properties and provide examples on how to use your component.&lt;/p&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;p class="MsoNormal"&gt;This post demonstrates how you can combine several AJAX extenders with other web UI elements into a nice, reusable package. You can use the code-behind of your web user controls to expose the properties, do error handling and set defaults.&lt;/p&gt;&lt;p class="MsoNormal"&gt;You can have a highly-functional generic control which will work well simply by adding it to a page. Through the various properties the developer can customize it to his or her desires making your control very flexible as well.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-6307143523079867328?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/6307143523079867328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=6307143523079867328' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/6307143523079867328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/6307143523079867328'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2009/01/using-web-user-controls-to-create-rich.html' title='Using Web User Controls to Create Rich Internet Application Subassembies - Part 2'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-2341449584107891642</id><published>2008-11-09T16:45:00.000-08:00</published><updated>2009-03-31T07:09:58.982-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Task List'/><category scheme='http://www.blogger.com/atom/ns#' term='web applicatons'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><category scheme='http://www.blogger.com/atom/ns#' term='Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Test Driver Design'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development Methods'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test Driven Development with Visual Studio 2008 Task Lists</title><content type='html'>&lt;h1&gt;Totally Integrated TDD Example&lt;/h1&gt;

&lt;p&gt;In my previous blog post,
&lt;a href="http://raywampler.blogspot.com/2008/10/use-visual-studio-task-list-to-create.html"&gt;Integrated TDD Environment&lt;/a&gt;, I
explained how you can do all of your Test Driven Delopment steps without leaving the Visual Studio 2008 IDE
by adding a new Task List comment type: TEST&lt;/p&gt;
&lt;p&gt;In this blog I will demonstrate step-by-step using a simple example how create a
functional class from scratch using integrated TDD within VS 2008.&lt;/p&gt;
&lt;h2&gt;The Requirements&lt;/h2&gt;
&lt;p&gt;Every software development project should begin with requirements. Our
example will have the following requirement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Provide a web form where the user can enter a temperature in either Fahrenheit
or Celsius and see the conversion to the other system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our design will separate the user interface from the business logic. For
our example we will only test the business logic. We start by creating a
new Windows class library project. Name it WebControls. Delete
Class1.cs and add a new class named Temperature. This is the class we will
build using TDD.&lt;/p&gt;
&lt;h2&gt;Generate the Test Project&lt;/h2&gt;
&lt;p&gt;Since we are doing TDD, then all of the development will be driven from our unit
tests. We want to have a test project for each project in our solution and
a test fixture for each class in each project. Lets add a new project to
our solution by selecting Project Type, "Test" and the "Test Project" template.
Name the project "WebControlsTestProject."&lt;/p&gt;
&lt;p&gt;Select WebControlsProjects in the solution explorer and select "Add" then "Unit
Test." You can then browse all the projects in your solution. Select
the Web Controls project and the Temperture class:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://4.bp.blogspot.com/_I28ndX8HWvo/SReFkHGeWfI/AAAAAAAAACc/5GUv7Qx0ESM/s1600-h/CreateUnitTest.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5266825144661072370" style="width: 320px;" alt="" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SReFkHGeWfI/AAAAAAAAACc/5GUv7Qx0ESM/s320/CreateUnitTest.JPG" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Visual Studio will create your unit test module shell with the necessary
includes and several procedures, including many that are commented out in the
"Additional test attributes" region, including setup and tear-down routines,
which you can easily uncomment and use.&lt;/p&gt;
&lt;p&gt;Since we created a class named "Temperature" then the Visual Studio unit test
wizard created a class called "TemperatureTest." We will add our test list
in this module.&lt;/p&gt;
&lt;h2&gt;
Add TEST to the Task List Comment Tokens&lt;/h2&gt;
&lt;p&gt;Start by defining a new Task List token for the test list. On the Tools
menu select Options, then select Task List from the list on the left of the
options dialog.&lt;/p&gt;
&lt;p&gt;
&lt;img alt="" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReGyshvQ1I/AAAAAAAAADE/tgMo4QdR7so/s320/AddTestTaskToken.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
Type "TEST" in the Name field, click Add and then OK. Now you will be able
add test list items anywhere in your code by adding a comment that begins with
the TEST: followed by the description of your test:&lt;/p&gt;
&lt;dl&gt;
&lt;dd&gt;
&lt;p class="style1"&gt;
// TEST: Here is a unit test description. &lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;This comment now appears on the Comments Task List:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://3.bp.blogspot.com/_I28ndX8HWvo/SReHbSJ4j3I/AAAAAAAAADs/xtM9GaQipos/s1600-h/FirstTaskOnList.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5266827192032595826" style="" alt="" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReHbSJ4j3I/AAAAAAAAADs/xtM9GaQipos/s320/FirstTaskOnList.JPG" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Create the Test List&lt;/h2&gt;
&lt;p&gt;
We are ready to create our test list. We start with our requirement and
test for the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Valid results&lt;/li&gt;
&lt;li&gt;Error conditions&lt;/li&gt;
&lt;li&gt;Limit conditions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you remember back to 6th grade, these are the key facts concerning conversion
between Fahrenheit and Celsius:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Water freezes at 32 F and 0 C&lt;/li&gt;
&lt;li&gt;Water boils at 100 C and 212 F&lt;/li&gt;
&lt;li&gt;The formula for converting is C = (5/9)*(F - 32)&lt;/li&gt;
&lt;li&gt;There is a temperature called "absolute zero" which is the lowest posible
temperature. It is -273.15 C or -459.67 F&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can make of these facts to generate the initial test list and then add more
tests as we think of them. Open the TemperatureTest.cs class file, move to
the end, and insert the following comments before the two end brackets for class
and namespace:&lt;/p&gt;
&lt;dl&gt;
&lt;dd&gt;
&lt;p&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify 32 F converts to 0 C&lt;/span&gt;
&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify 0 C converts to 32 F&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify 100 C converts to 212 F&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify 212 F converts to 100 C&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that the Celsius temperature equals Farenheit minus 32 times 5/9&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that the Farenheit temperature equals Celsius times 9/5 plus 32&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that a negative Farenheit temperture converts to the correct value&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that a negative Celsius temperture converts to the correct value&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that entering a temperture less than -273.15 C throws and exception&lt;/span&gt;
&lt;/p&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;span style="font-size:85%;"&gt;
}
}
&lt;/span&gt;
&lt;p&gt;If this doesn't cover all the code we need to write, it should give us a good
start. We can easily add new tests as we think of them just by entering
comments. Our VS Task List should now look like this:&lt;/p&gt;
&lt;img style="width: 680px;" alt="image" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReaizs5v1I/AAAAAAAAAFU/CncIaH1FlX8/s320/InitialTaskList.JPG" /&gt;
&lt;h2&gt;Implementing the Tests&lt;/h2&gt;
&lt;p&gt;We're now ready to start TDD. Let's start with the first test, "Verify 32
F converts to 0 C." You can double-click the item in the task list to jump
right to it. Add the following code below the comment:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 366px;" alt="Code01" src="http://1.bp.blogspot.com/_I28ndX8HWvo/SReZwF3fwKI/AAAAAAAAAEM/Fa5LZipWIVY/s320/FreezingFahrenheitTest.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;Now we want to write some code and see if the test passes. First we have a
design decision to make: do we want this class to require an object to be
instanited or use static methods?
Static methods are easier to call, but if we need data persisted
within the object we have a problem because static methods are global. If
you look back at the requirement we see that we need to support a web form,
which would have a view state, so our temperture convertor probably won't need to
remember anything. We'll start with a static method and hopefully that'll
get through all the tests.&lt;/p&gt;
&lt;p&gt;We start by writing the code in the test first, then updating the Temperture
class so that it compiles, and eventually passes the test.&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 607px;" alt="f1" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReZwzrNbMI/AAAAAAAAAEU/_pPyD0NTLBM/s320/FreezingFahrenheitTest1.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;It seems reasonable that the Temperature class would have a static method named
"ToCelsius" that takes a double (since we can have fractions of a degree)
representing the Fahrenheit temperature and returns the Celsius temperture as a
double.&lt;/p&gt;
&lt;p&gt;We have not written the "ToCelsius" method yet, so Visual Studio puts a wavy
red line under the method indicating a syntax error. Here is where the
refactoring capabilies come in handy. Hold the mouse over the
"ToCelsius" method name then you get a drop list where you can select "Generate
method stub for Temperature.ToCelsius." We do so and now we can compile
and run the test. Of course it fails:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 970px;" alt="f2" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReZyCppYDI/AAAAAAAAAEc/WLGMt6twJH8/s320/FreezingFahrenheitTest2.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;To fix the test we right-click the ToCelsius method "Go To Definition," and then
fix the method with the minimum amount of code for the test to pass:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 507px;" alt="f3" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReZzEl5QZI/AAAAAAAAAEk/gX6iRFpP178/s320/FreezingFahrenheitTest3.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;Run the test again and now it passes:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 522px;" alt="f4" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReZz4xW44I/AAAAAAAAAEs/pkO4blVStCY/s320/FreezingFahrenheitTest4.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;Our first test is done, so we remove it from the list. Since our Task
List is driven by comments then we need to delete the TEST: from the comment.
We can leave the description so that we have some documentation left behind.&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 593px;" alt="f5" src="http://1.bp.blogspot.com/_I28ndX8HWvo/SReaJOrbhBI/AAAAAAAAAE0/qjz8MgNpZ2M/s320/FreezingFahrenheitTest5.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;The Task List now has 8 tests remaining. The next test is to verify that 32
F converts to 0 C. If we follow the same method as before we write this
test:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 635px;" alt="f6" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReaJYbXQcI/AAAAAAAAAE8/l5mJza_obxQ/s320/FreezingFahrenheitTest6.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;We implement this method to get the tests to pass:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 473px;" alt="f7" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReaJzqZGyI/AAAAAAAAAFE/Lcja2FupaCI/s320/FreezingFahrenheitTest7.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;And we run all the tests and verify they pass:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 568px;" alt="f8" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SReaKJkiIRI/AAAAAAAAAFM/3_Vw8vNEqic/s320/FreezingFahrenheitTest8.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;Note that there are actually 3 tests, because Visual Studio automatically adds a
test for the class constructor. Since we're using static methods and don't
do anything in the construtor, then I changed the default test to simply verify
that the class can be created:&lt;/p&gt;
&lt;p&gt;&lt;img style="width: 378px;" alt="ct" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReHaXQTNaI/AAAAAAAAADM/2rPWBW5ryKA/s320/ConstructorTest.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;When we did the freezing point tests we wrote the minimum amount of code by
simply returning the hard-coded expected results of 0 or 32. We could do
the same with the boiling points, but let's skip
ahead a couple tests and see if these two tests don't take care of some of the
others:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;
&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that the Celsius temperature equals Farenheit minus 32 times 5/9&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that the Farenheit temperature equals Celsius times 9/5 plus 32&lt;/span&gt;&lt;span style="font-size:85%;"&gt;
&lt;/span&gt;
&lt;/dt&gt;
&lt;/dl&gt;
&lt;p&gt;
Again we start by writing the test code first, then adjusting the class methods
for the tests to pass. We can use the same to static method to convert
Fahrenheit to Celsius and copy the previous test, then edit the code to create
the test below:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 686px;" alt="to Celsius" src="http://1.bp.blogspot.com/_I28ndX8HWvo/SReaj0pMtpI/AAAAAAAAAFk/Td5N_nxFjew/s320/ToCelsius01.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
For the above test I picked a random temperature, 72 F, and then calculated what
the result should be. We now run the test, and since our "ToCelsius" mthod
is still hard-coded to return 0 then, of course, it fails:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 863px;" alt="to celsius test result" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReakI0pFXI/AAAAAAAAAFs/2heoKOM21n0/s320/ToCelsius02.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
We can now go to the ToCelsius method and fix it:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 472px;" alt="to celsius method" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SReaknSgcNI/AAAAAAAAAF0/w_PjIbztN4M/s320/ToCelsius03.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
Let's rerun the tests and see what happens:&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://1.bp.blogspot.com/_I28ndX8HWvo/SReax17Qv5I/AAAAAAAAAF8/9rfdmMN7B3s/s1600-h/ToCelsius04.JPG"&gt;&lt;img id="Img1" style="width: 320px;" alt="" src="http://1.bp.blogspot.com/_I28ndX8HWvo/SReax17Qv5I/AAAAAAAAAF8/9rfdmMN7B3s/s320/ToCelsius04.JPG" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
Notice that not only does the ConvertToCelsiusTest pass, but the previous tests
also pass so that we know we have not broken any of the previously working code
with our new changes. That's one of the benefits of TDD: as you build your
software in small steps you build a collection of regression test that get
re-run at each step, immediately alerting you when when new code causes previous
code to fail.&lt;/p&gt;
&lt;p&gt;
At this point I won't bore you too much more with doing the next few tests step-by-step.
The Convert to Fahrenheit test can be done the same way we just did the Celsius
conversion, and the two boiling point tests can be added and run to check that
our formulas work at both ends of the scale:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 535px;" alt="tests" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReajpmiS-I/AAAAAAAAAFc/x3qtsMe856M/s320/TestRun02.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
Now we have one more test to do:&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that entering a temperture less than -273.15 C throws and exception&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
But this suggests one companion test, verifying that absolute zero on the
Fahrenheit scale also generates an exception. We can quickly add tests as
we think of them by simply typing in a comment:&lt;/p&gt;
&lt;p&gt;
&lt;span style="color: rgb(0, 128, 0);font-size:85%;" &gt;// TEST: Verify that entering a temperture less
than -459.67 F throws and exception&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
Let's do absolute zero on the Celsius scale first. This is different from
the previous tests, because instead of testing an assertion, we want to test
that certain will generate an exception. So we need to use the
ExpectedException attribute. We add it as a decoration inside square
brackets between the TestMethod() attribute and the unit test method
declaration. It takes a parameter for the expected exception type, so
that's the first thing we need to decide, the type of exception we should
generate. We could define our own custom exception, but lets just use an
Overflow Exception, since we are overflowing the range of valid temperatures.
Here's what the test code would look like:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 688px;" alt="Abs0CelsiusTestCode" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SReGxMEWMGI/AAAAAAAAACk/cfzmipuFjJw/s320/Abs0CelsiusTestCode.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
Notice that we added the ExpectedException attribute and gave it the
System.OverflowException parameter, using the typeof() function to provide the
correct type for the parameter. The test code itself does not need to use
the Assert method. The test method just needs to execute code we expect to
generate the exception. So we take the out-of-range Celsius value, give it
to the ToFahrenheit method, and try to assign it to a variable. When we
run this test we get the following result:&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_I28ndX8HWvo/SReGx8s9R0I/AAAAAAAAAC8/P8thwTK-kc0/s1600-h/Abs0CelsiusTestResult.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5266826481899489090" style="width: 320px;" alt="" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReGx8s9R0I/AAAAAAAAAC8/P8thwTK-kc0/s320/Abs0CelsiusTestResult.JPG" border="0" /&gt;&lt;/a&gt;
&lt;p&gt;
The code did not throw an exception, therefore the test failed. We now
adjust the ToFahrenheit to throw the expected exception:&lt;/p&gt;
&lt;p&gt;
&lt;img alt="Abs test fix" src="http://1.bp.blogspot.com/_I28ndX8HWvo/SReGxTcyNxI/AAAAAAAAACs/5CVzomVRePc/s320/Abs0CelsiusTestFix.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
The test now passes:&lt;/p&gt;
&lt;p&gt;
&lt;img style="width: 524px;" alt="Abs0CelsiusTestFixResult" src="http://3.bp.blogspot.com/_I28ndX8HWvo/SReGxuuXpSI/AAAAAAAAAC0/D0cbMfkkAWg/s320/Abs0CelsiusTestFixResult.JPG" /&gt;&lt;/p&gt;
&lt;p&gt;
The process for the absolute zero Fahrenheit is similar. We add the test,
adjust the code ustil it passes, then we can re-run all our tests and they now
all pass:&lt;/p&gt;
&lt;a href="http://2.bp.blogspot.com/_I28ndX8HWvo/SReHbLWsreI/AAAAAAAAADk/9UYTZChsFlk/s1600-h/FinalTestsResult.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5266827190207294946" style="width: 320px;" alt="" src="http://2.bp.blogspot.com/_I28ndX8HWvo/SReHbLWsreI/AAAAAAAAADk/9UYTZChsFlk/s320/FinalTestsResult.JPG" border="0" /&gt;&lt;/a&gt;
&lt;p&gt;
We keep removing the TEST: attribute from our comments each time a test passes
and our Task List is now empty:&lt;/p&gt;
&lt;a href="http://4.bp.blogspot.com/_I28ndX8HWvo/SReHa2ULTbI/AAAAAAAAADc/uICaZEwLzZY/s1600-h/FinalTaskList.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5266827184559574450" style="width: 320px;" alt="" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SReHa2ULTbI/AAAAAAAAADc/uICaZEwLzZY/s320/FinalTaskList.JPG" border="0" /&gt;&lt;/a&gt;
&lt;h2&gt;
Summary&lt;/h2&gt;
&lt;p&gt;
This demonstrates how you can do TDD, Test Driven Development, without leaving
the Visual Studio 2008 environment. We added a new task type, TEST and
then managed our TDD test list through the Task List. We used the
integrated unit test and refactoring capabilities of VS 2008 to build a new
class from scratch using the red/green/refactor methodology.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-2341449584107891642?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/2341449584107891642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=2341449584107891642' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2341449584107891642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2341449584107891642'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2008/11/test-driven-development-with-visual.html' title='Test Driven Development with Visual Studio 2008 Task Lists'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_I28ndX8HWvo/SReFkHGeWfI/AAAAAAAAACc/5GUv7Qx0ESM/s72-c/CreateUnitTest.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-2929490899655054168</id><published>2008-10-19T21:27:00.000-07:00</published><updated>2009-01-07T13:58:55.794-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reusable subassemblies'/><category scheme='http://www.blogger.com/atom/ns#' term='web user controls'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='Rich Internet Applications'/><category scheme='http://www.blogger.com/atom/ns#' term='RIA'/><category scheme='http://www.blogger.com/atom/ns#' term='extender design pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='extenders'/><category scheme='http://www.blogger.com/atom/ns#' term='custom web user interface'/><category scheme='http://www.blogger.com/atom/ns#' term='web applicaitons'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX Control Toolkit'/><title type='text'>Using Web User Controls to Create Rich Internet Application Subassembies</title><content type='html'>&lt;div class="Section1"&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-family:Georgia;"&gt;Web user controls provide
an opportunity to combine multiple related controls into one neat package. If
you combine standard form elements with components from the &lt;a href="http://www.codeplex.com/AjaxControlToolkit"&gt;AJAX control toolkit&lt;/a&gt; then
you can build a library of rich internet application elements.&lt;/span&gt;&lt;/p&gt;&lt;h2&gt;Example: A Numeric Entry Control&lt;/h2&gt;&lt;p class="MsoNormal"&gt;To illustrate what I mean, let’s consider a basic web user
control for numeric data entry. Of the basic HTML form elements, text box,
check box, list box, radio button, etc., the only one that would work for
entering numbers is the text box. But the text box will allow you to enter
either text or numbers, so if you have a data entry field for a numeric values
then you would need to supplement it by adding either server-side or
client-side code to prevent the user from entering anything other than numbers.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Since this is a common programming task, it would be nice if
we could make a generic control for numeric entry that we could then easily
reuse anytime we need numeric data input.&lt;/p&gt;&lt;p class="MsoNormal"&gt;The requirements for this control are:&lt;/p&gt;&lt;ul style="MARGIN-TOP: 0in" type="disc"&gt;&lt;li class="MsoNormal"&gt;It will only accept numeric values&lt;/li&gt;
&lt;li class="MsoNormal"&gt;You can set a minimum and maximum value&lt;/li&gt;
&lt;li class="MsoNormal"&gt;You can set it accept either integers or decimal numbers&lt;/li&gt;
&lt;li class="MsoNormal"&gt;You can set it add comma separators if desired&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;AJAX Control Subassemblies&lt;/h3&gt;&lt;p class="MsoNormal"&gt;We can make use of Microsoft’s AJAX Control Toolkit to
perform the client-side tasks which will limit the user to entering only
numbers within a specified range into a textbox. &lt;/p&gt;&lt;p class="MsoNormal"&gt;The AJAX Control Toolkit uses the “extender” design
pattern. What this means is that instead of creating specialized controls that
that will do one particular task, they offer control extenders which all have a
“target control” parameter. The extender adds some additional capability or
feature to its target. Different extenders can operate on the same target
control. This gives more flexibility for adding exactly the features and
behaviors that you desire in a particular control.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Scott Guthrie has a great discussion of &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/08/19/using-asp-net-ajax-control-extenders-in-vs-2008.aspx"&gt;ASP.Net
control extenders&lt;/a&gt; in his blog.&lt;/p&gt;&lt;p class="MsoNormal"&gt;The disadvantage is that every time you want to add a
particular type of control that makes use of multiple AJAX extenders then you
have to combine all the parts together and wire them up for each and every
field on every web page. We can give up a little flexibility but still have
very useful generic components by creating web user control subassemblies that
combine elements that are commonly used together.&lt;/p&gt;&lt;p class="MsoNormal"&gt;The properties of the subassemblies are:&lt;/p&gt;&lt;ul style="MARGIN-TOP: 0in" type="disc"&gt;&lt;li class="MsoNormal"&gt;Two or more extenders are pre-wired to a common target
control&lt;/li&gt;
&lt;li class="MsoNormal"&gt;The web user control assembly exposes public properties
that control the key attributes of the extenders&lt;/li&gt;
&lt;li class="MsoNormal"&gt;The extenders will have reasonable default values so that
you can drop the web user control onto your web page and use it with a
minimal amount of effort, setting only those properties that are unique to
the specific field.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;AJAX Extenders for our Sample Numeric Control&lt;/h2&gt;&lt;p class="MsoNormal"&gt;We can meet the above requirements be making use of the
following AJAX extender controls:&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;table class="MsoTableGrid" style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none; BORDER-COLLAPSE: collapse" cellspacing="0" cellpadding="0" border="1"&gt;&lt;tbody&gt;&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; WIDTH: 95.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="127"&gt;
&lt;p class="MsoNormal"&gt;&lt;b&gt;Control&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 347.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="463"&gt;
&lt;p class="MsoNormal"&gt;&lt;b&gt;Description (from &lt;a href="http://www.asp.net/"&gt;http://www.asp.net/&lt;/a&gt;
)&lt;/b&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; WIDTH: 95.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="127"&gt;
&lt;p class="MsoNormal"&gt;&lt;a href="http://www.asp.net/AJAX/AjaxControlToolkit/Samples/MaskedEdit/MaskedEdit.aspx"&gt;MaskedEdit&lt;/a&gt;
&lt;/p&gt;
&lt;/td&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 347.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="463"&gt;
&lt;p class="MsoNormal"&gt;MaskedEdit is an ASP.NET AJAX extender that attaches to a
TextBox control to restrict the kind of text that can be entered. MaskedEdit
applies a "mask" to the input that permits only certain types of
characters/text to be entered. The supported data formats are: Number, Date,
Time, and DateTime.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: windowtext 1pt solid; WIDTH: 95.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="127"&gt;
&lt;p class="MsoNormal"&gt;&lt;a href="http://quickstarts.asp.net/QuickStartv20/aspnet/doc/validation/default.aspx#range"&gt;RangeValidator&lt;/a&gt;&lt;/p&gt;
&lt;/td&gt;&lt;td style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: medium none; PADDING-LEFT: 5.4pt; PADDING-BOTTOM: 0in; BORDER-LEFT: medium none; WIDTH: 347.4pt; PADDING-TOP: 0in; BORDER-BOTTOM: windowtext 1pt solid" valign="top" width="463"&gt;
&lt;p class="MsoNormal"&gt;The RangeValidator server control tests whether an input
value falls within a given range. RangeValidator uses three key properties to
perform its validation. ControlToValidate contains the value to validate.
MinimumValue and MaximumValue define the minimum and maximum values of the
valid range.&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
The range validator is actually a standard ASP.Net control
but it does use the same extender design pattern. You will often combine
validation controls with text boxes and AJAX extenders. By preassembling these
parts you can save yourself some work.&lt;/p&gt;&lt;p class="MsoNormal"&gt;In my next post I will take you step-by-step through a real-world
example by creating a web user control subassembly for numeric data input.&lt;/p&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;p class="MsoNormal"&gt;The AJAX Control Toolkit and other ASP.Net components such
as validators use the Extender Design Pattern, which makes them very flexible
for adding features and behaviors to existing controls and allowing you to pick
and choose multiple extenders to work on the same control. The drawback is
that you have to do a lot more work to custom define the features and behaviors
of every individual control that you desire to have a rich user interface. You
can reduce this effort by creating a subassembly that combines ASP.Net AJAX and
other web interface components into a web user control.&lt;/p&gt;&lt;p class="MsoNormal"&gt;One example of such a web user control is a numeric data
input control which I describe here and will create in &lt;a href="http://raywampler.blogspot.com/2009/01/using-web-user-controls-to-create-rich.html"&gt;my next post&lt;/a&gt;.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-2929490899655054168?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/2929490899655054168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=2929490899655054168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2929490899655054168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/2929490899655054168'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2008/10/using-web-user-controls-to-create-rich.html' title='Using Web User Controls to Create Rich Internet Application Subassembies'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-3711448645836115016</id><published>2008-10-11T10:01:00.000-07:00</published><updated>2008-11-17T08:14:07.646-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Test Driven Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Task List'/><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008 SP 1'/><category scheme='http://www.blogger.com/atom/ns#' term='Software'/><category scheme='http://www.blogger.com/atom/ns#' term='Test Driver Design'/><category scheme='http://www.blogger.com/atom/ns#' term='Software Development Methods'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Use Visual Studio Task List to Create Test Lists for Test Driven Development</title><content type='html'>&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-6263659-1");
pageTracker._trackPageview();
&lt;/script&gt;
&lt;h1&gt;Integrated TDD Environment&lt;/h1&gt;&lt;h2&gt;Introduction&lt;/h2&gt;The Visual Studio 2008 SP1 now includes integrated unit testing, making TDD (Test Driven Development or Test Driven Development) easier than ever before. However, if you want to use VS 2008 as a fully-integrated TDD environment, you'll need to make creative use of the Task List.

&lt;h2&gt;Test Driven Design and Development&lt;/h2&gt;The idea behind TDD is that you write all the code for your application through a series of small steps by creating unit tests. The mantra is, "Never write a single line of code unless you have a test that fails."

There are a couple advanatages to doing it this way:
&lt;ul&gt;&lt;li&gt;By doing things in small steps, you can go quicker with less errors&lt;/li&gt;
&lt;li&gt;You create unit tests as you go and rerun them with each coding change, immediately finding any code that gets broken when you add new features&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So how do you start?&lt;/p&gt;&lt;p&gt;Like any software project, TDD starts with requirements. What does the software &lt;em&gt;need&lt;/em&gt; to do? You take each requirement and generate a "test list," a list of all the criteria that must be met to fulfill the requirement. &lt;/p&gt;&lt;p&gt;The basic TDD process is Red/Green/Refactor:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Write a test that fails so that the unit test shows a red light&lt;/li&gt;
&lt;li&gt;Add code to make the test pass and show a green light&lt;/li&gt;
&lt;li&gt;Refactor to avoid duplication&lt;/li&gt;&lt;/ol&gt;&lt;h2&gt;Using Visual Studio as TDD Environment&lt;/h2&gt;&lt;p&gt;Visual Studio now helps with this process. Visual Studio 2008 Professional Edition now includes the Visual Studio Test Suite (previously only Team Edition had it) which gives you the red and green lights. The Visual Studio editor also includes some built-in refactoring support. &lt;/p&gt;&lt;p&gt;However I would like to do &lt;em&gt;everything&lt;/em&gt; within a single IDE if possible. I would prefer to do the Test Lists within my code editor rather than entering them into a spreadsheet, text file, or writting them down on paper. One way to do this is with the Visual Studio Task List. &lt;/p&gt;&lt;h2&gt;Visual Studio Task List&lt;/h2&gt;&lt;p&gt;The Task List has been part of VS since the original .Net 1.0 release. It provides a mechanism for reminders of things that developers need to complete. &lt;/p&gt;&lt;p&gt;You can open the Task List by selecting it from the View menu. There are two types of tasks: User and Comments. User tasks are things that you enter manually and manage yourself. Comments are created by adding comments with special key words to your code. You can then jump from your task list to the spot in the code where you put the comment.&lt;/p&gt;&lt;p&gt;Visual Studio provides three default tokens for comment tasks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;TODO: Something that needs to be started or completed. VS will automatically generate some of these, for example when you create a new class it adds, "TODO: Add constructor logic here."&lt;/li&gt;
&lt;li&gt;HACK: Quickly written code that needs to be reworked later.&lt;/li&gt;
&lt;li&gt;UNDONE: Code changes that have been reversed.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To create a comment you enter the comment characters, (// in C#, ' in VB), the token followed by a colon (:) and the text of the task.&lt;/p&gt;&lt;p&gt;We can use the Task List for TDD by adding our own comment token: TEST.&lt;/p&gt;&lt;p&gt;To add a custom token we select options from the Tools menu and then select Task List under Environment:&lt;/p&gt;&lt;p&gt;&lt;a href="http://4.bp.blogspot.com/_I28ndX8HWvo/SPD2qM6hR5I/AAAAAAAAABw/0Vj3-4kc6aw/s1600-h/TaskListOptions.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5255971970022983570" style="WIDTH: 591px; CURSOR: hand; HEIGHT: 325px" height="223" alt="" src="http://4.bp.blogspot.com/_I28ndX8HWvo/SPD2qM6hR5I/AAAAAAAAABw/0Vj3-4kc6aw/s320/TaskListOptions.JPG" width="483" border="0" /&gt;&lt;/a&gt;

To add our new token we enter TEST in the Name field and then click Add. We can now add a Test Task anywhere in our code by starting a comment, typing TEST: and a description of our test.

Now you can create your TDD test list right inside the VS source code editor for your test project.:

&lt;span style="font-family:Courier New;color:#009900;"&gt;// TEST: Verify a user can add a new record
// TEST: Verify a user can update an existing record
// TEST: Verify a user can delete an existing record
// TEST: Verify an error occurs when add a duplicate record&lt;/span&gt;

&lt;a href="http://2.bp.blogspot.com/_I28ndX8HWvo/SQPdQvN-FWI/AAAAAAAAACU/6QpUaXb6iWo/s1600-h/TaskListTests.JPG"&gt;&lt;img id="BLOGGER_PHOTO_ID_5261292069321577826" style="WIDTH: 600px; CURSOR: hand; alt: " src="http://2.bp.blogspot.com/_I28ndX8HWvo/SQPdQvN-FWI/AAAAAAAAACU/6QpUaXb6iWo/s320/TaskListTests.JPG" border="0" /&gt;&lt;/a&gt;

To implement each test you add your test code after the comment and delete the &lt;span style="color:#009900;"&gt;TEST:&lt;/span&gt; part of the comment to remove the test from the Task List:&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color:#009900;"&gt;// Verify a user can add a new record
&lt;/span&gt;[&lt;span style="color:#33ccff;"&gt;TestMethod&lt;/span&gt;()]
&lt;span style="color:#000099;"&gt;public void&lt;/span&gt; AddNewRecord()
{
&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color:#009900;"&gt;// TODO: Add Test Logic
&lt;/span&gt;}&lt;/span&gt;&lt;/p&gt;&lt;p&gt;As you think of new tests while your in the middle of coding others you add a &lt;span style="color:#009900;"&gt;TEST: &lt;/span&gt;comment and then go back to what you're working on. Later, you can double-click on an item in the Task List to go directly to that spot in the code.&lt;/p&gt;&lt;p&gt;In my next blog post I'll walk you through a simple example.
&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-3711448645836115016?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/3711448645836115016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=3711448645836115016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/3711448645836115016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/3711448645836115016'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2008/10/use-visual-studio-task-list-to-create.html' title='Use Visual Studio Task List to Create Test Lists for Test Driven Development'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_I28ndX8HWvo/SPD2qM6hR5I/AAAAAAAAABw/0Vj3-4kc6aw/s72-c/TaskListOptions.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-6244124830952552662</id><published>2008-10-11T08:19:00.000-07:00</published><updated>2008-10-11T09:29:51.385-07:00</updated><title type='text'>Happy not to be Spam</title><content type='html'>This is first cold morning of the season here in Colorado.  I'm sipping my Starbuck's pumpkin spice latte and rejoicing that my blog has been cleared by the Blogger spam cops.   You see, soon after I posted my first entry I received an email saying, "Your blog has been identified as a potential spam blog.  To correct this, please request a review by filling out the form [here]."  I checked my blog this morning and it's all back to normal again.  I've been approved.

Now that I've been approved, where do I start?  Yesterday a was a bit of downer at work.  It was the last day for several of the contractors because the company I work for is feeling the credit crunch and economic downturn that is dominating the news now.   Last week was the "worst week in stock market history."  I've heard that before.  The economy goes in cycles.  We're near the bottom now, there's brighter days.  It's just hard to believe it at the moment, but we can ride the coming bull market to success.

After working in IT for 20 years I've come to accept the fact that software developers are an expense that every business needs to minimize in order to be successful.  The key to success as a programmer is to be a partner with your employers to deliver the highest quality software at the lowest cost possible.

Today we have many tools and methodologies to help achieve that goal.  In future blog posts I will be covering things like the newest versions of languages and developer tools, Test Driven Development, MVC, agile development, combining it all together into the "Get 'er Done" methodology.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-6244124830952552662?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/6244124830952552662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=6244124830952552662' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/6244124830952552662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/6244124830952552662'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2008/10/happy-not-to-be-spam.html' title='Happy not to be Spam'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6181362549951896980.post-7924012133809465790</id><published>2008-10-05T21:21:00.000-07:00</published><updated>2008-10-05T21:38:00.199-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='toastmasters'/><category scheme='http://www.blogger.com/atom/ns#' term='health'/><category scheme='http://www.blogger.com/atom/ns#' term='Colorado'/><category scheme='http://www.blogger.com/atom/ns#' term='Introduction'/><category scheme='http://www.blogger.com/atom/ns#' term='volleyball'/><title type='text'>Finally starting to blog</title><content type='html'>Hi,
My name is Ray Wampler and this is my first blog.  Why would anyone want read a blog by me?  There are a few areas where I have some expertise that other people might find interesting:
&lt;ul&gt;&lt;li&gt;I've worked in the IT/Software industry for over 20 years for a variety of companies and industries.  I keep up on the latest technologies and trends.&lt;/li&gt;&lt;li&gt;I've been in Toastmasters for 8 years, earning the distinction of Advnaced Communicator Silver and Advanced Leader Silver, and I'm currently working on my Distinguished Toastmaster.&lt;/li&gt;&lt;li&gt;I keep informed on a variety of topics including health and nutrition, travel, volleyball, business, and investing.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These subjects will hopefully provide a wealth of topics for interesting and entertaining blog posts.  I plan to add to this blog on a regular basis, providing usefull information to my readers.&lt;/p&gt;&lt;p&gt;Regards,&lt;/p&gt;&lt;p&gt;Ray Wampler&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6181362549951896980-7924012133809465790?l=raywampler.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://raywampler.blogspot.com/feeds/7924012133809465790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6181362549951896980&amp;postID=7924012133809465790' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/7924012133809465790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6181362549951896980/posts/default/7924012133809465790'/><link rel='alternate' type='text/html' href='http://raywampler.blogspot.com/2008/10/finally-starting-to-blog.html' title='Finally starting to blog'/><author><name>Ray Wampler</name><uri>http://www.blogger.com/profile/00482533094769971625</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://3.bp.blogspot.com/_I28ndX8HWvo/SOuGLepEesI/AAAAAAAAABU/dk-h1-BZ2oU/S220/ray3x4.jpg'/></author><thr:total>0</thr:total></entry></feed>
