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

<channel>
	<title>TechShorts</title>
	<atom:link href="http://blog.ddpruitt.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ddpruitt.net</link>
	<description>Improving the development process one day at a time.</description>
	<lastBuildDate>Wed, 28 Jan 2009 18:10:00 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using IDataErrorInfo for Validation</title>
		<link>http://blog.ddpruitt.net/2009/01/28/using-idataerrorinfo-for-validation/</link>
		<comments>http://blog.ddpruitt.net/2009/01/28/using-idataerrorinfo-for-validation/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 18:10:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2009/01/28/using-idataerrorinfo-for-validation/</guid>
		<description><![CDATA[I read an article on CodeProject titled Total View Validation where the author complains that IDataErrorInfo is inadequate for WPF validation.&#160; The assumption he makes is that all the validation code needs to go into the IDataErrorInfo.this[string] property as such:

publicstringthis[string name]
{
&#160;&#160; get
&#160;&#160;&#160; {
&#160;&#160;&#160; &#160;&#160;&#160; string result = null;
&#160;&#160;&#160; &#160;&#160;&#160; if (name == &#34;Age&#34;)
&#160;&#160;&#160; &#160;&#160;&#160; {
&#160;&#160;&#160; [...]]]></description>
			<content:encoded><![CDATA[<p>I read an article on <a href="http://www.codeproject.com" zid="3">CodeProject</a> titled <a href="http://www.codeproject.com/KB/WPF/GlobalWPFValidation.aspx" zid="5">Total View Validation</a> where the author complains that IDataErrorInfo is inadequate for WPF validation.&nbsp; The assumption he makes is that all the validation code needs to go into the IDataErrorInfo.this[string] property as such:<br zid="6"/><br zid="7"/><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red240\green240\blue240;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1\cb2\highlight2 public\cf0  \cf1 string\cf0  \cf1 this\cf0 [\cf1 string\cf0  name]\par ??\{\par ??   \cf1 get\par ??\cf0     \{\par ??        \cf1 string\cf0  result = \cf1 null\cf0 ;\par ??        \cf1 if\cf0  (name == \cf4 "Age"\cf0 )\par ??        \{\par ??            \cf1 if\cf0  (\cf1 this\cf0 .age &lt; 0 || \cf1 this\cf0 .age &gt; 150)\par ??            \{\par ??                result = \cf4 "Age must not be less than 0 or greater than 150."\cf0 ;\par ??            \}\par ??        \}\par ??        \cf1 return\cf0  result;\par ??    \}\par ??\}} -->
<div style="background: rgb(240, 240, 240) none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" zid="492">
<pre style="margin: 0px;" zid="493"><span style="color: blue;" zid="494">public</span><span style="color: blue;" zid="495">string</span><span style="color: blue;" zid="496">this</span>[<span style="color: blue;" zid="497">string</span> name]</pre>
<pre style="margin: 0px;" zid="498">{</pre>
<pre style="margin: 0px;" zid="499">&nbsp;&nbsp; <span style="color: blue;" zid="500">get</span></pre>
<pre style="margin: 0px;" zid="501">&nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="502">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="503">string</span> result = <span style="color: blue;" zid="504">null</span>;</pre>
<pre style="margin: 0px;" zid="505">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="506">if</span> (name == <span style="color: rgb(163, 21, 21);" zid="507">&quot;Age&quot;</span>)</pre>
<pre style="margin: 0px;" zid="508">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="509">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="510">if</span> (<span style="color: blue;" zid="511">this</span>.age &lt; 0 || <span style="color: blue;" zid="512">this</span>.age &gt; 150)</pre>
<pre style="margin: 0px;" zid="513">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="514">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; result = <span style="color: rgb(163, 21, 21);" zid="515">&quot;Age must not be less than 0 or greater than 150.&quot;</span>;</pre>
<pre style="margin: 0px;" zid="516">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="517">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="518">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="519">return</span> result;</pre>
<pre style="margin: 0px;" zid="520">&nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="521">}</pre>
</div>
<p><br zid="23"/>This should not be the way that IDataErrorInfo is used as it puts business logic in the model, as the author points out.&nbsp; His solution though was to create another mechanism to notifiy the user of validation errors and to not use IDataErrorInfo at all.<br zid="24"/><br zid="25"/>A solution I would propose though would be to follow how DataTables and DataTables use IDataErrorInfo by implementing methods to set and clear the objects error information:<br zid="26"/><br zid="27"/><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red240\green240\blue240;\red0\green0\blue0;\red0\green128\blue0;\red163\green21\blue21;\red43\green145\blue175;}??\fs20 \cf1\cb2\highlight2 #region\cf0  Data Error Info\par ??\par ??        \cf1 private\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt; _propertyErrors;\par ??\par ??        \cf1 private\cf0  \cf1 void\cf0  InitDataErrorInfo()\par ??        \{\par ??            var properties = \cf1 this\cf0 .GetType().GetProperties();\par ??\par ??            _propertyErrors = \cf1 new\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt;();\par ??\par ??            \cf4 // This will act as an overall error message for the entire object.\par ??\cf0             _propertyErrors.Add(\cf1 this\cf0 .GetHashCode().ToString(), \cf1 string\cf0 .Empty);\par ??\par ??            \cf1 foreach\cf0  (var propertyInfo \cf1 in\cf0  properties)\par ??            \{\par ??                _propertyErrors.Add(propertyInfo.Name, \cf1 string\cf0 .Empty);\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo()\par ??        \{\par ??            \cf1 foreach\cf0  (var property \cf1 in\cf0  _propertyErrors.Keys)\par ??            \{\par ??                _propertyErrors[property] = \cf1 string\cf0 .Empty;\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo(\cf1 string\cf0  propertyName)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Empty;\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  error)\par ??        \{\par ??            SetError(\cf1 this\cf0 .GetHashCode().ToString(), error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  propertyName, \cf1 string\cf0  error)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Format(\cf5 "\{0\}\{1\}\{2\}"\cf0 , _propertyErrors[propertyName], \cf6 Environment\cf0 .NewLine,  error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  \cf1 this\cf0 [\cf1 string\cf0  propertyName]\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                AssertThisHasPropertyWithName(propertyName);\par ??                \cf1 return\cf0  _propertyErrors[propertyName];\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Error\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                var errors = \cf1 new\cf0  StringBuilder();\par ??                \cf1 foreach\cf0  (var propertyError \cf1 in\cf0  _propertyErrors)\par ??                \{\par ??                    \cf1 if\cf0  (\cf1 string\cf0 .IsNullOrEmpty(propertyError.Value)) \cf1 continue\cf0 ;\par ??\par ??                    errors.AppendLine(propertyError.Value);\par ??                \}\par ??\par ??                \cf1 return\cf0  errors.ToString().Trim();\par ??            \}\par ??        \}\par ??\par ??        \cf1 protected\cf0  \cf1 void\cf0  AssertThisHasPropertyWithName(\cf1 string\cf0  propertyName)\par ??        \{\par ??            \cf1 if\cf0  (!_propertyErrors.ContainsKey(propertyName))\par ??            \{\par ??                \cf1 throw\cf0  \cf1 new\cf0  \cf6 ArgumentException\cf0 (\cf1 string\cf0 .Format(\cf5 "No property named \{0\} on \{1\}."\cf0 , propertyName, \cf1 this\cf0 .GetType().FullName));\par ??            \}\par ??        \}\par ??\par ??\cf1         #endregion} --><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red240\green240\blue240;\red0\green0\blue0;\red0\green128\blue0;\red163\green21\blue21;\red43\green145\blue175;}??\fs20 \cf1\cb2\highlight2 public\cf0  SomeClass() : IDataErrorInfo\par ??\tab \{\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Name \{ \cf1 get\cf0 ; \cf1 set\cf0 ; \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Age \{ \cf1 get\cf0 ; \cf1 set\cf0 ; \}\par ??\par ??\cf1 \tab \tab #region\cf0  Data Error Info\par ??\par ??        \cf1 private\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt; _propertyErrors;\par ??\par ??        \cf1 private\cf0  \cf1 void\cf0  InitDataErrorInfo()\par ??        \{\par ??            var properties = \cf1 this\cf0 .GetType().GetProperties();\par ??\par ??            _propertyErrors = \cf1 new\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt;();\par ??\par ??            \cf4 // This will act as an overall error message for the entire object.\par ??\cf0             _propertyErrors.Add(\cf1 this\cf0 .GetHashCode().ToString(), \cf1 string\cf0 .Empty);\par ??\par ??            \cf1 foreach\cf0  (var propertyInfo \cf1 in\cf0  properties)\par ??            \{\par ??                _propertyErrors.Add(propertyInfo.Name, \cf1 string\cf0 .Empty);\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo()\par ??        \{\par ??            \cf1 foreach\cf0  (var property \cf1 in\cf0  _propertyErrors.Keys)\par ??            \{\par ??                _propertyErrors[property] = \cf1 string\cf0 .Empty;\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo(\cf1 string\cf0  propertyName)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Empty;\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  error)\par ??        \{\par ??            SetError(\cf1 this\cf0 .GetHashCode().ToString(), error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  propertyName, \cf1 string\cf0  error)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Format(\cf5 "\{0\}\{1\}\{2\}"\cf0 , _propertyErrors[propertyName], \cf6 Environment\cf0 .NewLine,  error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  \cf1 this\cf0 [\cf1 string\cf0  propertyName]\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                AssertThisHasPropertyWithName(propertyName);\par ??                \cf1 return\cf0  _propertyErrors[propertyName];\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Error\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                var errors = \cf1 new\cf0  StringBuilder();\par ??                \cf1 foreach\cf0  (var propertyError \cf1 in\cf0  _propertyErrors)\par ??                \{\par ??                    \cf1 if\cf0  (\cf1 string\cf0 .IsNullOrEmpty(propertyError.Value)) \cf1 continue\cf0 ;\par ??\par ??                    errors.AppendLine(propertyError.Value);\par ??                \}\par ??\par ??                \cf1 return\cf0  errors.ToString().Trim();\par ??            \}\par ??        \}\par ??\par ??        \cf1 protected\cf0  \cf1 void\cf0  AssertThisHasPropertyWithName(\cf1 string\cf0  propertyName)\par ??        \{\par ??            \cf1 if\cf0  (!_propertyErrors.ContainsKey(propertyName))\par ??            \{\par ??                \cf1 throw\cf0  \cf1 new\cf0  \cf6 ArgumentException\cf0 (\cf1 string\cf0 .Format(\cf5 "No property named \{0\} on \{1\}."\cf0 , propertyName, \cf1 this\cf0 .GetType().FullName));\par ??            \}\par ??        \}\par ??\par ??\cf1         #endregion\par ??\cf0 \tab \}\par ??} --><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red240\green240\blue240;\red0\green0\blue0;\red0\green128\blue0;\red163\green21\blue21;\red43\green145\blue175;}??\fs20 \cf1\cb2\highlight2 public\cf0  SomeClass() : IDataErrorInfo\par ??\tab \{\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Name \{ \cf1 get\cf0 ; \cf1 set\cf0 ; \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Age \{ \cf1 get\cf0 ; \cf1 set\cf0 ; \}\par ??\par ??\cf1 \tab \tab #region\cf0  Data Error Info\par ??\par ??        \cf1 private\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt; _propertyErrors;\par ??\par ??        \cf1 private\cf0  \cf1 void\cf0  InitDataErrorInfo()\par ??        \{\par ??            var properties = \cf1 this\cf0 .GetType().GetProperties();\par ??\par ??            _propertyErrors = \cf1 new\cf0  Dictionary&lt;\cf1 string\cf0 , \cf1 string\cf0 &gt;();\par ??\par ??            \cf4 // This will act as an overall error message for the entire object.\par ??\cf0             _propertyErrors.Add(\cf1 this\cf0 .GetHashCode().ToString(), \cf1 string\cf0 .Empty);\par ??\par ??            \cf1 foreach\cf0  (var propertyInfo \cf1 in\cf0  properties)\par ??            \{\par ??                _propertyErrors.Add(propertyInfo.Name, \cf1 string\cf0 .Empty);\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo()\par ??        \{\par ??            \cf1 foreach\cf0  (var property \cf1 in\cf0  _propertyErrors.Keys)\par ??            \{\par ??                _propertyErrors[property] = \cf1 string\cf0 .Empty;\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  ClearDataErrorInfo(\cf1 string\cf0  propertyName)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Empty;\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  error)\par ??        \{\par ??            SetError(\cf1 this\cf0 .GetHashCode().ToString(), error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 void\cf0  SetError(\cf1 string\cf0  propertyName, \cf1 string\cf0  error)\par ??        \{\par ??            AssertThisHasPropertyWithName(propertyName);\par ??            _propertyErrors[propertyName] = \cf1 string\cf0 .Format(\cf5 "\{0\}\{1\}\{2\}"\cf0 , _propertyErrors[propertyName]\par ??                , \cf6 Environment\cf0 .NewLine,  error);\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  \cf1 this\cf0 [\cf1 string\cf0  propertyName]\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                AssertThisHasPropertyWithName(propertyName);\par ??                \cf1 return\cf0  _propertyErrors[propertyName];\par ??            \}\par ??        \}\par ??\par ??        \cf1 public\cf0  \cf1 string\cf0  Error\par ??        \{\par ??            \cf1 get\par ??\cf0             \{\par ??                var errors = \cf1 new\cf0  StringBuilder();\par ??                \cf1 foreach\cf0  (var propertyError \cf1 in\cf0  _propertyErrors)\par ??                \{\par ??                    \cf1 if\cf0  (\cf1 string\cf0 .IsNullOrEmpty(propertyError.Value)) \cf1 continue\cf0 ;\par ??\par ??                    errors.AppendLine(propertyError.Value);\par ??                \}\par ??\par ??                \cf1 return\cf0  errors.ToString().Trim();\par ??            \}\par ??        \}\par ??\par ??        \cf1 protected\cf0  \cf1 void\cf0  AssertThisHasPropertyWithName(\cf1 string\cf0  propertyName)\par ??        \{\par ??            \cf1 if\cf0  (!_propertyErrors.ContainsKey(propertyName))\par ??            \{\par ??                \cf1 throw\cf0  \cf1 new\cf0  \cf6 ArgumentException\cf0 (\cf1 string\cf0 .Format(\cf5 "No property named \{0\} on \{1\}."\par ??\cf0                     , propertyName, \cf1 this\cf0 .GetType().FullName));\par ??            \}\par ??        \}\par ??\par ??\cf1         #endregion\par ??\cf0 \tab \}} -->
<div style="background: rgb(240, 240, 240) none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;" zid="331">
<pre style="margin: 0px;" zid="332"><span style="color: blue;" zid="333">public</span> SomeClass() : IDataErrorInfo</pre>
<pre style="margin: 0px;" zid="334">&nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="335">&nbsp;</pre>
<pre style="margin: 0px;" zid="336">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="337">public</span><span style="color: blue;" zid="338">string</span> Name { <span style="color: blue;" zid="339">get</span>; <span style="color: blue;" zid="340">set</span>; }</pre>
<pre style="margin: 0px;" zid="341">&nbsp;</pre>
<pre style="margin: 0px;" zid="342">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="343">public</span><span style="color: blue;" zid="344">string</span> Age { <span style="color: blue;" zid="345">get</span>; <span style="color: blue;" zid="346">set</span>; }</pre>
<pre style="margin: 0px;" zid="347">&nbsp;</pre>
<pre style="margin: 0px;" zid="348"><span style="color: blue;" zid="349">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #region</span> Data Error Info</pre>
<pre style="margin: 0px;" zid="350">&nbsp;</pre>
<pre style="margin: 0px;" zid="351">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="352">private</span> Dictionary&lt;<span style="color: blue;" zid="353">string</span>, <span style="color: blue;" zid="354">string</span>&gt; _propertyErrors;</pre>
<pre style="margin: 0px;" zid="355">&nbsp;</pre>
<pre style="margin: 0px;" zid="356">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="357">private</span><span style="color: blue;" zid="358">void</span> InitDataErrorInfo()</pre>
<pre style="margin: 0px;" zid="359">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="360">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var properties = <span style="color: blue;" zid="361">this</span>.GetType().GetProperties();</pre>
<pre style="margin: 0px;" zid="362">&nbsp;</pre>
<pre style="margin: 0px;" zid="363">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors = <span style="color: blue;" zid="364">new</span> Dictionary&lt;<span style="color: blue;" zid="365">string</span>, <span style="color: blue;" zid="366">string</span>&gt;();</pre>
<pre style="margin: 0px;" zid="367">&nbsp;</pre>
<pre style="margin: 0px;" zid="368">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;" zid="369">// This will act as an overall error message for the entire object.</span></pre>
<pre style="margin: 0px;" zid="370">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors.Add(<span style="color: blue;" zid="371">this</span>.GetHashCode().ToString(), <span style="color: blue;" zid="372">string</span>.Empty);</pre>
<pre style="margin: 0px;" zid="373">&nbsp;</pre>
<pre style="margin: 0px;" zid="374">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="375">foreach</span> (var propertyInfo <span style="color: blue;" zid="376">in</span> properties)</pre>
<pre style="margin: 0px;" zid="377">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="378">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors.Add(propertyInfo.Name, <span style="color: blue;" zid="379">string</span>.Empty);</pre>
<pre style="margin: 0px;" zid="380">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="381">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="382">&nbsp;</pre>
<pre style="margin: 0px;" zid="383">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="384">public</span><span style="color: blue;" zid="385">void</span> ClearDataErrorInfo()</pre>
<pre style="margin: 0px;" zid="386">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="387">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="388">foreach</span> (var property <span style="color: blue;" zid="389">in</span> _propertyErrors.Keys)</pre>
<pre style="margin: 0px;" zid="390">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="391">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors[property] = <span style="color: blue;" zid="392">string</span>.Empty;</pre>
<pre style="margin: 0px;" zid="393">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="394">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="395">&nbsp;</pre>
<pre style="margin: 0px;" zid="396">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="397">public</span><span style="color: blue;" zid="398">void</span> ClearDataErrorInfo(<span style="color: blue;" zid="399">string</span> propertyName)</pre>
<pre style="margin: 0px;" zid="400">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="401">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; AssertThisHasPropertyWithName(propertyName);</pre>
<pre style="margin: 0px;" zid="402">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors[propertyName] = <span style="color: blue;" zid="403">string</span>.Empty;</pre>
<pre style="margin: 0px;" zid="404">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="405">&nbsp;</pre>
<pre style="margin: 0px;" zid="406">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="407">public</span><span style="color: blue;" zid="408">void</span> SetError(<span style="color: blue;" zid="409">string</span> error)</pre>
<pre style="margin: 0px;" zid="410">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="411">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SetError(<span style="color: blue;" zid="412">this</span>.GetHashCode().ToString(), error);</pre>
<pre style="margin: 0px;" zid="413">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="414">&nbsp;</pre>
<pre style="margin: 0px;" zid="415">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="416">public</span><span style="color: blue;" zid="417">void</span> SetError(<span style="color: blue;" zid="418">string</span> propertyName, <span style="color: blue;" zid="419">string</span> error)</pre>
<pre style="margin: 0px;" zid="420">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="421">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; AssertThisHasPropertyWithName(propertyName);</pre>
<pre style="margin: 0px;" zid="422">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; _propertyErrors[propertyName] = <span style="color: blue;" zid="423">string</span>.Format(<span style="color: rgb(163, 21, 21);" zid="424">&quot;{0}{1}{2}&quot;</span>, _propertyErrors[propertyName]</pre>
<pre style="margin: 0px;" zid="425">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , <span style="color: rgb(43, 145, 175);" zid="426">Environment</span>.NewLine,&nbsp; error);</pre>
<pre style="margin: 0px;" zid="427">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="428">&nbsp;</pre>
<pre style="margin: 0px;" zid="429">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="430">public</span><span style="color: blue;" zid="431">string</span><span style="color: blue;" zid="432">this</span>[<span style="color: blue;" zid="433">string</span> propertyName]</pre>
<pre style="margin: 0px;" zid="434">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="435">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="436">get</span></pre>
<pre style="margin: 0px;" zid="437">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="438">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; AssertThisHasPropertyWithName(propertyName);</pre>
<pre style="margin: 0px;" zid="439">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="440">return</span> _propertyErrors[propertyName];</pre>
<pre style="margin: 0px;" zid="441">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="442">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="443">&nbsp;</pre>
<pre style="margin: 0px;" zid="444">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="445">public</span><span style="color: blue;" zid="446">string</span> Error</pre>
<pre style="margin: 0px;" zid="447">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="448">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="449">get</span></pre>
<pre style="margin: 0px;" zid="450">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="451">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var errors = <span style="color: blue;" zid="452">new</span> StringBuilder();</pre>
<pre style="margin: 0px;" zid="453">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="454">foreach</span> (var propertyError <span style="color: blue;" zid="455">in</span> _propertyErrors)</pre>
<pre style="margin: 0px;" zid="456">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="457">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="458">if</span> (<span style="color: blue;" zid="459">string</span>.IsNullOrEmpty(propertyError.Value)) <span style="color: blue;" zid="460">continue</span>;</pre>
<pre style="margin: 0px;" zid="461">&nbsp;</pre>
<pre style="margin: 0px;" zid="462">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; errors.AppendLine(propertyError.Value);</pre>
<pre style="margin: 0px;" zid="463">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="464">&nbsp;</pre>
<pre style="margin: 0px;" zid="465">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="466">return</span> errors.ToString().Trim();</pre>
<pre style="margin: 0px;" zid="467">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="468">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="469">&nbsp;</pre>
<pre style="margin: 0px;" zid="470">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="471">protected</span><span style="color: blue;" zid="472">void</span> AssertThisHasPropertyWithName(<span style="color: blue;" zid="473">string</span> propertyName)</pre>
<pre style="margin: 0px;" zid="474">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="475">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="476">if</span> (!_propertyErrors.ContainsKey(propertyName))</pre>
<pre style="margin: 0px;" zid="477">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</pre>
<pre style="margin: 0px;" zid="478">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;" zid="479">throw</span><span style="color: blue;" zid="480">new</span><span style="color: rgb(43, 145, 175);" zid="481">ArgumentException</span>(<span style="color: blue;" zid="482">string</span>.Format(<span style="color: rgb(163, 21, 21);" zid="483">&quot;No property named {0} on {1}.&quot;</span></pre>
<pre style="margin: 0px;" zid="484">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; , propertyName, <span style="color: blue;" zid="485">this</span>.GetType().FullName));</pre>
<pre style="margin: 0px;" zid="486">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="487">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</pre>
<pre style="margin: 0px;" zid="488">&nbsp;</pre>
<pre style="margin: 0px;" zid="489"><span style="color: blue;" zid="490">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; #endregion</span></pre>
<pre style="margin: 0px;" zid="491">&nbsp;&nbsp;&nbsp; }</pre>
</div>
<p><br zid="171"/><br zid="170"/>  Note that there is no validation here, only reporting if the object has errors.&nbsp; Using this takes advantage of the already existing validation notification built into WPF as well as WinForms.<br zid="4"/></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2009/01/28/using-idataerrorinfo-for-validation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Y2K38</title>
		<link>http://blog.ddpruitt.net/2009/01/09/y2k38/</link>
		<comments>http://blog.ddpruitt.net/2009/01/09/y2k38/#comments</comments>
		<pubDate>Fri, 09 Jan 2009 14:53:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2009/01/09/y2k38/</guid>
		<description><![CDATA[Eight seconds past 3:14 a.m., on January 19, 2038, most computers in the world will think it’s actually a quarter to 9 p.m. on December 13, 1901.
Oh Crap.
]]></description>
			<content:encoded><![CDATA[<p>Eight seconds past 3:14 a.m., on January 19, 2038, most computers in the world will think it’s actually a quarter to 9 p.m. on December 13, 1901.</p>
<p>Oh Crap.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2009/01/09/y2k38/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Changing Typed DataSet Connection String</title>
		<link>http://blog.ddpruitt.net/2008/05/13/changing-typed-dataset-connection-string/</link>
		<comments>http://blog.ddpruitt.net/2008/05/13/changing-typed-dataset-connection-string/#comments</comments>
		<pubDate>Tue, 13 May 2008 20:26:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/05/13/changing-typed-dataset-connection-string/</guid>
		<description><![CDATA[I was working on a WinForm app that connected to a MS Access database.  Yeah, Access sucks but I didn&#8217;t have a choice in the matter.
The app itself is used to import a bunch of CSV files into the Access database.  It is more of a utility program and it has going through [...]]]></description>
			<content:encoded><![CDATA[<p>I was working on a WinForm app that connected to a MS Access database.  Yeah, Access sucks but I didn&#8217;t have a choice in the matter.</p>
<p>The app itself is used to import a bunch of CSV files into the Access database.  It is more of a utility program and it has going through several variations, from being a simple hand driven command line tool to being GUI driven.</p>
<p>The command line version was all hand controlled.  I had to go in and update configuration files to point to the CSV files and the MDB database.  That got old fast so I decided to make a GUI version that would allow me to pick the MDB file and each of the CSV files to import.  Picking and using the CSV files was easy, it was changing the connection string for the MDB that proved to be the hardest.</p>
<p>I am using strongly typed datasets in VS2005.  If you have ever worked with them you find out soon that the connection string gets saved with the project in the app.config file, even if it is a seperate DAL dll project.  My guess is that Microsoft assumed that if you ever had a connection to one database then your strongly typed dataset would not have to change to another database, but if you did you could always just update the configuration file.</p>
<p>As my drill instructor was always fond of saying:  &#8220;Wrong f***ing answer!&#8221;</p>
<p>I wanted, in the case, to use a strongly typed dataset.  I also wanted to use different Access files, and I wanted to be able to select which Access file I used while the application was running.  Why is that so hard?</p>
<p>I searched the web and found several not so useful suggestions.  It appears that there are two camps of people for this issue:  Those that understood what I wanted to do and were trying to do it also, and those that didn&#8217;t understand what the problem was.</p>
<p>Those in the latter camp always resorted to the same suggestion:  Just update the configuration files to point to the new database.  This doesn&#8217;t work in this case because I would then have to restart the app in order for the new setting to be picked up.</p>
<p>The other popular option was to completely re-write the Settings.Designer.cs file so that when the DataTables called to get the connection string it would call a method you created so you could pass anything into it you wanted.  The problem with this approach is that if you changed any of the other settings then your code would get over-written by Visual Studio.</p>
<p>The least popular option was to go to each DataTable and create partial classes that override the InitConnection() method.  This royally sucks if you have lots of DataTables.</p>
<p>In the Settings class, all Connection String types are application level and cannot be made into User Settings.  This leads to the other issue, namely all Connection String settings are read-only.  But this is true only for saving the connection string, which is not something I needed to do.  I just need to be able to change it.</p>
<p>Also the Settings class is internal and sealed, which means it cannot be accessed from outside of the current project.  So my GUI project cannot directly access my DAL project and update the Settings value.  To get around that limitation I just created a proxy class.  The resulting class is:</p>
<p><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red43\green145\blue175;\red0\green128\blue0;\red163\green21\blue21;}??\fs20 \cf1 using\cf0  DC.Catalog.DAL.Properties;\par ??\par ??\cf1 namespace\cf0  DC.Catalog.DAL\par ??\{\par ??    \cf1 public\cf0  \cf1 static\cf0  \cf1 class\cf0  \cf4 EquipmentConnectionSettings\par ??\cf0     \{\par ??        \cf1 public\cf0  \cf1 static\cf0  \cf1 void\cf0  SetEquipmentToConnectToMdb(\cf1 string\cf0  MdbFilename)\par ??        \{\par ??            \cf5 // This only overrides the in-memory copy of the setting.  It is not perminate.\par ??\cf0             \cf4 Settings\cf0 .Default[\cf6 "EquipmentConnectionString"\cf0 ] = \cf1 string\cf0 .Format(\par ??                \cf4 Settings\cf0 .Default.EquipmentConnectionStringTemplate\par ??                , MdbFilename);\par ??        \}\par ??    \}\par ??\}} -->
<div style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:black;">
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    1</span> <span style="color:blue;">using</span> DC.Catalog.DAL.Properties;</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    2</span> </pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    3</span> <span style="color:blue;">namespace</span> DC.Catalog.DAL</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    4</span> {</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    5</span>     <span style="color:blue;">public </span><span style="color:blue;">static</span><span style="color:blue;"> class</span><span style="color: rgb(43, 145, 175);">EquipmentConnectionSettings</span></pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    6</span>     {</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    7</span>         <span style="color:blue;">public </span><span style="color:blue;">static </span><span style="color:blue;">void</span> SetEquipmentToConnectToMdb(<span style="color:blue;">string</span> MdbFilename)</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    8</span>         {</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">    9</span>             <span style="color:green;">// This only overrides the in-memory copy of the setting.  It is not perminate.</span></pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   10</span>             <span style="color: rgb(43, 145, 175);">Settings</span>.Default[<span style="color: rgb(163, 21, 21);">"EquipmentConnectionString"</span>] = <span style="color:blue;">string</span>.Format(</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   11</span>                 <span style="color: rgb(43, 145, 175);">Settings</span>.Default.EquipmentConnectionStringTemplate</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   12</span>                 , MdbFilename);</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   13</span>         }</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   14</span>     }</pre>
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">   15</span> }</pre>
</div>
<p>Notice that to update the setting value I had to use:</p>
<p><!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red43\green145\blue175;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 Settings\cf0 .Default[\cf4 "EquipmentConnectionString"\cf0 ]} -->
<div style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 40px;font-family:Courier New;font-size:10pt;color:black;">
<pre style="margin: 0px;"><span style="color: rgb(43, 145, 175);">Settings</span>.Default[<span style="color: rgb(163, 21, 21);">"EquipmentConnectionString"</span>]</pre>
</div>
<p><span style="font-family:monospace;">Since the setting </span><span style="color: rgb(43, 145, 175);font-family:courier new,courier,monospace;" >Settings</span><span style="font-family:courier new,courier,monospace;">.Default.</span><span style="color: rgb(163, 21, 21);"><span style="font-family:courier new,courier,monospace;">EquipmentConnectionString</span> </span><span style="font-family:verdana;">is readonly I had to use the other way to access the value.  The EquipmentConnectionStringTemplate is simple: </p>
<p></span>
<div style="margin-left: 40px;"><span style="font-family:courier new,courier,monospace;">Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}</span><br /><span style="font-family:verdana;"></span></div>
<p><span style="font-family:verdana;"><br />Every time I change the Access file I am pointing at I call the SetEquipmentToConnectToMdb() method, magic happens in the Typed DataSet and it all just works.</p>
<p></span><span style="font-family:monospace;"></span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/05/13/changing-typed-dataset-connection-string/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>DataSets &#8211; Love em Hate em</title>
		<link>http://blog.ddpruitt.net/2008/02/09/datasets-love-em-hate-em/</link>
		<comments>http://blog.ddpruitt.net/2008/02/09/datasets-love-em-hate-em/#comments</comments>
		<pubDate>Sun, 10 Feb 2008 03:12:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/02/09/datasets-love-em-hate-em/</guid>
		<description><![CDATA[I have a love-hate relationship with DataSets.&#160; On the one hand they are easy to use and contain lots of built in functionality.&#160; On the other hand they are abused by almost everyone but at the same time severely under utilized, meaning that I rarely see anyone use most of the features available.I get the [...]]]></description>
			<content:encoded><![CDATA[<p>I have a love-hate relationship with DataSets.&nbsp; On the one hand they are easy to use and contain lots of built in functionality.&nbsp; On the other hand they are abused by almost everyone but at the same time severely under utilized, meaning that I rarely see anyone use most of the features available.<br zid="2"/><br zid="3"/>I get the feeling that the majority of developers that use DataSets have blinders on:&nbsp; DataSets are only useful for reading and writing data to the database.&nbsp; End of story.&nbsp; If you are an ASP.NET developer you absolutely refuse to use them and use DataReaders only.&nbsp; And in the last three years I have not seen too many applications that use the typed DataSets that can be created in Visual Studio 2005.<br zid="5"/><br zid="4"/>I don&#8217;t like using DataSets because I prefer to use NHibernate or ActiveRecord to interact with databases.&nbsp; But lately I have been having a change of heart as I have been delving more and more into using DataSets in the application I am currently working on.&nbsp; There is a lot of functionality baked into DataSets that I have been overlooking and since I have been working with the strongly typed DataSets generated by VS 2005 I have to ask myself why I need to recreate it with POCO&#8217;s.<br zid="8"/><br zid="9"/>The way I am looking at DataSets now is not as an in-memory relational database but as a highly versatile data structure that handles a lot of things I need it to handle:&nbsp; Relationships, constraints, databinding, serializable and data error information.&nbsp; Sometimes I see it as being nothing more than a collection of Hashtables, each Hashtable being another collection of Hashtables.&nbsp; And the fact that there is a designer to work with it makes it better.<br zid="10"/><br zid="11"/>I worked on a home grown messaging system project, the message object orginated as an XSD that got converted to C# classes using the xsd.exe tool.&nbsp; The tool didn&#8217;t work to well (this was in .NET 1.1) so all the names and name spaces were so screwed that most of the classes had the name space in the class name.&nbsp; Intellisense really sucked at times.&nbsp; Me being who I am I started trying to figure out a simpler message object when it donned on me that a DataSet would have been a perfect fit for what they were doing.&nbsp; A .NET 1.1 DataSet serialized to XML was ugly but in 2.0 it got a much needed face lift.&nbsp;&nbsp; You should have seen them laugh at me when I suggested switching the message object out.&nbsp; &#8220;You dummy, DataSets are for Databases!!&nbsp; Ha Ha Ha, we&#8217;re writing SOAP messages!&#8221;&nbsp; <br zid="12"/><br zid="13"/>Yeah, I left that place.<br zid="14"/><br zid="15"/>When it comes to data binding DataSets can&#8217;t be beat.&nbsp; WinForms have been especially built for binding to DataSets.&nbsp; One thing I wished that would be easy to do is to bind one DataSet to another without using&nbsp; form.&nbsp; Currently I have a form that has two user controls, each with its own DataSet that require data in one form to update data in the other.&nbsp; I am working on a way to databind the two DataSets together, currently the form is manually updating the data in the other DataSet as it changes.&nbsp; I want to pull all the code out of the forms and create a Database Synch Service.<br zid="16"/><br zid="17"/>A lot of the data validation I have seen in OPA&#8217;s (other peoples apps) has been in the form.&nbsp; Typcially if an error occurs a nice little pop-up shows some nasty message then either won&#8217;t let the user save the data or reverts it back to a previous value.&nbsp; DataSets have a way to set a Row and Column with a specific error message which can be used by the form to indicate there is an error.<br zid="18"/><br zid="19"/>As for the actual validation, I want to create a <a href="http://ebersys.blogspot.com/2006/09/dictionaries-of-methods-in-c.html" target="_blank" title="Dictionaries of methods in C#" zid="20">dictionary of methods</a>&nbsp; to validate the DataTables and DataColumns.&nbsp; The validators would take the row, column and DataSet being validated and the validation errors will be entered using the rows SetColumnError method.<br zid="21"/><br zid="22"/>Still though, DataSets are going to become mute when Linq comes out.&nbsp; Maybe.<br zid="7"/></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/02/09/datasets-love-em-hate-em/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Value Objects as Measurement Objects</title>
		<link>http://blog.ddpruitt.net/2008/02/05/value-objects-as-measurement-objects/</link>
		<comments>http://blog.ddpruitt.net/2008/02/05/value-objects-as-measurement-objects/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 04:42:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/02/05/value-objects-as-measurement-objects/</guid>
		<description><![CDATA[So I was reviewing PEAA looking to see if Fowler had come up with the idea of Measurment Objects, that horse I&#8217;ve been kicking around lately.&#160; I found that he has a couple of close patterns:&#160; Value Object and Money.
Value Object:&#160; A small simple object, like money or a date range, whose equality isn&#8217;t based [...]]]></description>
			<content:encoded><![CDATA[<p>So I was reviewing PEAA looking to see if Fowler had come up with the idea of Measurment Objects, that horse I&#8217;ve been kicking around lately.&nbsp; I found that he has a couple of close patterns:&nbsp; Value Object and Money.</p>
<p>Value Object:&nbsp; <span style="font-style: italic;"  >A small simple object, like money or a date range, whose equality isn&#8217;t based on identity.</span></p>
<p>Money: <span style="font-style: italic;"  >Represents a monetary value.</span></p>
<p>According to Fowler&nbsp;Value Objects are light weight and almost primative types.&nbsp; They should also me immutable since they have no identity.&nbsp; He also suggests that in .NET structs could be used as Value Objects.</p>
<p>The money pattern looks like a special case of a Measurement Object with the UnitOfMeasure being set to currency (currency being USD or Euro).</p>
<p>I see the usefulness of using structs but there is the boxing issue if we implement them with interfaces.</p>
<p>I will have to ponder on this.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/02/05/value-objects-as-measurement-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Measurement Objects</title>
		<link>http://blog.ddpruitt.net/2008/02/04/measurement-objects/</link>
		<comments>http://blog.ddpruitt.net/2008/02/04/measurement-objects/#comments</comments>
		<pubDate>Tue, 05 Feb 2008 04:14:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/02/04/measurement-objects/</guid>
		<description><![CDATA[In my previous post I described setting up a database to track measurements.&#160; I ran into problems quickly with the data model and I could see that it was going to become a convoluted mess pretty quick.&#160; So I want to take a step back and look at it from an application point of view.
What [...]]]></description>
			<content:encoded><![CDATA[<p>In my previous post I described setting up a database to track measurements.&nbsp; I ran into problems quickly with the data model and I could see that it was going to become a convoluted mess pretty quick.&nbsp; So I want to take a step back and look at it from an application point of view.</p>
<p>What I want is a way to track an objects measurements.&nbsp; I need a system that is easy to understand, any one looking at an object should readily understand what each measurement property is and what units it is in.&nbsp; The system should accommodate almost any existing system of measurement but at the same time it needs to be simple.&nbsp; Brain dead simple.</p>
<p><img align="bottom" alt="Measurement Object Diagram" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=344506000000008001/1202182817737_MeasurementObject.png&#038;accId=344506000000002007" vspace="0"  /><br />What I am thinking is to start out with a abstract base class for our Measurement Object.&nbsp; It has an ID that can be an int, string or Guid, take your pick.&nbsp; The Text property is the string representation of the Value, Value being in an abstract class that extends MeasurementBase.</p>
<p>I think that it is important to seperate the actual Value into another class of Type T.&nbsp; This allows us to create collections of MeasurementBase objects and add MeasurementBase&lt;T&gt; objects to it.&nbsp; I am still struggling with this idea as it totally blows apart expectations on what a Value is (is it an int?&nbsp; a DateTime?), but this is the reason I stuck the Text property on the MeasrumentBase.&nbsp; The Text property takes care of the conversion of the string representation to the actual Value.</p>
<p>Already this is getting complicated.&nbsp; What is it I&#8217;m trying to do here?</p>
<p>My ultimate goal is to have the means to convert a measurment from one system to another.&nbsp; The objects themselves should take care of the conversion.&nbsp; The way I have seen it in the past is to have conversion code scattered throughout the entire application layer, including the UI and the data access layer.</p>
<p>This is one of those ideas that is on the tip of my neurons, I know it has been solved before but I haven&#8217;t found it.&nbsp; And every time I start working on it I naturally want to drop into the Database thinking frame of mind.</p>
<p>I need to review some of the Enterprise Patterns, see if it already exits.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/02/04/measurement-objects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Databases Suck</title>
		<link>http://blog.ddpruitt.net/2008/01/30/databases-suck/</link>
		<comments>http://blog.ddpruitt.net/2008/01/30/databases-suck/#comments</comments>
		<pubDate>Thu, 31 Jan 2008 04:55:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/01/30/databases-suck/</guid>
		<description><![CDATA[I am sick of working with databases, they all suck. &#160;I can generalize this to any type of data store, they all suck.
OK, they don&#8217;t really suck but I sure have seen a lot of database designs that do.&#160; I am tired of working with applications that have lots and lots of large tables, tables [...]]]></description>
			<content:encoded><![CDATA[<p>I am sick of working with databases, they all suck. &nbsp;I can generalize this to any type of data store, they all suck.</p>
<p>OK, they don&#8217;t really suck but I sure have seen a lot of database designs that do.&nbsp; I am tired of working with applications that have lots and lots of large tables, tables with lots and lots of fields.&nbsp; Of course all the fields but the primary key are nullable because you might not always need that extra address field but it is there, just in case.</p>
<p>And don&#8217;t get me started on compound primary keys.&nbsp; If I see tables with compound primary keys then I am trying to get off of that project.</p>
<p>What if we have to change the database, add a field, remove a field or just plain rename a field?&nbsp; Well that just broke the application, not just the code you own but the code in a module you never heard of that the reporting team is using.&nbsp; Why can we not update schema&#8217;s without worrying about causing the build to fail?</p>
<p>And what about all the boiler plate code needed to communicate with your database?&nbsp; We have to invest in code generators that get it about 80% right.&nbsp; Then the databinding to the forms, after all a database does no good unless you can get data into it.</p>
<p>So how do we solve this problem?&nbsp; Get ride of the database?&nbsp; Use only CSV files?&nbsp; Go back to pencils and paper?&nbsp; Those are options but not necessarily good ones.&nbsp; We have the technology so why not use it, only use it in a different way.</p>
<p>What are we trying to do with the database any way?&nbsp; Store values so we can retrieve them later.</p>
<p>What about history?&nbsp; How do we know when someone changed a value?&nbsp; And what was the value before?</p>
<p>What is a value?&nbsp; If we don&#8217;t know what it is we are storing then how are we going to know how to store it?</p>
<p>Based on the majority of the applications I have worked on values tend to be descriptions or measurements.&nbsp; Descriptions are remarks, model numbers, serial numbers or some other form of text that has meaning to the object.&nbsp; Measurements are attributes of an object that magnitude relative to some unit of measurement system.&nbsp;&nbsp;<a href="http://en.wikipedia.org/wiki/Measurement" target="" title=""  >Wikipeda</a> has a better description of it than I do so check it out then come back.</p>
<p>Note that this is not a new idea, I read about measurement values somewhere but I can&#8217;t for the life of me find who actually came up with it orginally.&nbsp; And if you really want to get technical about measurement values there are scalers (magnitude only) and vectors (magnitude and direction).</p>
<p>So how do we handle this in databases?&nbsp; First we create a measurement table like such:
<div style="text-align: right;"  >
<div style="text-align: center;"  ><img align="absmiddle" alt="Measurement Table" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=344506000000007001/1201752124371_MeasurementTable.png&#038;accId=344506000000002007" vspace="0"  /></div>
<div style="text-align: left;"  >This table is pretty basic:&nbsp; You have your primary key Id, the magnitude of the measurement is the value and the system used is determined by the UnitOfMeasurement.&nbsp; The CreatedBy and CreatedOn is for audit and historical purposes.&nbsp; To maintain a history in the database we will not allow deletes from this table, only inserts.&nbsp; This allows us to see all the changes made to this value when they were made and by who.&nbsp; The value that was added last is the current value.</p>
<p>Now that we have the measurement what exactly are we measuring?&nbsp; We need some properties of some kind.&nbsp; So we need a Property table and a link to the Measurement table.
<div style="text-align: center;"  ><img align="bottom" alt="Property Measurement" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=344506000000007001/1201752957798_PropertyMeasurement.png&#038;accId=344506000000002007" vspace="0"  /></div>
<p>We have the Id again which becomes the foreign key in the Measurement table.&nbsp; The name is what the property is called and the TypeOfMeasurement is the attribute being measure.&nbsp; This could be length, mass, weight, currency, velocity, acceleration, etc.&nbsp; Note that it is the UnitOfMeasurement in the Measurement table that dictates if we use feet, meters, kilograms, pounds, US Dollars, Euros, meters per second, etc.</p>
<p>What do these properties apply to though?&nbsp; We need an object that has properties:
<div style="text-align: center;"  ><img align="bottom" alt="Object Properties" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=344506000000007001/1201753728226_objectProperties.png&#038;accId=344506000000002007" vspace="0"  /></div>
<p>Now this is just getting crazy.&nbsp; Our object can have many properties but also our properties can belong to many objects.&nbsp; We will have to work that little kink out but for now I think I will stop playing with pictures.</p>
<p>What is it I really am trying to do?&nbsp; I want to reduce the pain of making changes to the database for an application.&nbsp; What does that mean?</p>
<p>Let us say for example we create an app that needs to track squares.&nbsp; Nothing fancy, just a square.&nbsp; Our first instinct is to create a table such as:<br /><img align="bottom" alt="Square" border="0" hspace="0" src="http://writer.zoho.com:80/ImageDisplay.im?name=344506000000007001/1201754189141_square.png&#038;accId=344506000000002007" vspace="0"  /></p>
<p>After building many forms and reports off of our square table management comes along and says we need to track cubes!&nbsp; Those eF&#8217;ers! &nbsp;You have to go back, change the name of the table, wait, no just leave the name the same, I&#8217;ll remember what it really should be.&nbsp; Add the new column Height, modify all the data access code, forms and reports to use the new value and life goes on.</p>
<p>Till six months later when management comes back and says that some federal requirements mandate that all changes to the cubes be tracked for three years.&nbsp; So you look for your cube table which doesn&#8217;t exist.&nbsp; There is this square table with all the right fields, but squares don&#8217;t have height, they are flat!&nbsp; Screw it just add a history table, copy the rows as they are changed, create some triggers, job done.</p>
<p>Except management finds out that Canada has been entering values in metric but in the states it is in feet.&nbsp; Plus Canada has been updating some of the US&#8217;es cubes.&nbsp; Now is the time to get the resume ready.</p>
<p>Databases suck.&nbsp; Working with databases is a pain but it really shouldn&#8217;t be.&nbsp; This extends beyond databases, it applies to objects as well.&nbsp; How to stop the pain?&nbsp; Stop adding values directly to the table.&nbsp; Granted this is not a 100% solution, I mean really if I had a square object I wouldn&#8217;t worry a lot about keeping track of two fields.</p>
<p>But if I had some complicated object that had many properties, and I was still in the development cycle where all of the properties still had not been identified, I think I would take the Measurement table approach.</div>
</div>
<p> Technorati Tags &nbsp; &nbsp; <a href=http://technorati.com/tag/database  rel=tag>database</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/01/30/databases-suck/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blogging from Zoho</title>
		<link>http://blog.ddpruitt.net/2008/01/16/blogging-from-zoho/</link>
		<comments>http://blog.ddpruitt.net/2008/01/16/blogging-from-zoho/#comments</comments>
		<pubDate>Wed, 16 Jan 2008 19:50:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/01/16/blogging-from-zoho/</guid>
		<description><![CDATA[So I decided to give Zoho a spin to see if it is better than Google Docs.  So far it seems pretty impressive, more document like.  Google Docs feels like I have little or no control over the final document.
But the one thing that suprised me:  I can post my document to [...]]]></description>
			<content:encoded><![CDATA[<p>So I decided to give Zoho a spin to see if it is better than Google Docs.  So far it seems pretty impressive, more document like.  Google Docs feels like I have little or no control over the final document.</p>
<p>But the one thing that suprised me:  I can post my document to my blog!  Man that just made my whole life eaiser!  I was wanting something to use for <a href="http://techshorts.blogspot.com/" target="" title="">TechShorts</a> but did not really like using the available Blogger editor.  I could use BlogJet or Live Writer but I want to be able to blog from my eee PC, which is Linux based.</p>
<p>Zoho to the rescue.</p>
<p><a href="http://technorati.com/tag/bloggerD" rel="tag"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/01/16/blogging-from-zoho/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Get this party started</title>
		<link>http://blog.ddpruitt.net/2008/01/06/get-this-party-started/</link>
		<comments>http://blog.ddpruitt.net/2008/01/06/get-this-party-started/#comments</comments>
		<pubDate>Mon, 07 Jan 2008 03:27:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/01/06/get-this-party-started/</guid>
		<description><![CDATA[Do you want this party started Right?Or do you want this party started Quickly!?Where to begin?  How about trying to figure out what this blog is for, that is always a good thing to start with.
It is about Technical stuff.  Short technical stuff.  I want a place that I can brain dump [...]]]></description>
			<content:encoded><![CDATA[<p>Do you want this party started <span style="font-style: italic;">Right?<span style="font-style: italic;"><br /></span></span>Or do you want this party started <span style="font-style: italic;">Quickly!?<br /><span style="font-style: italic;"><br /></span></span>Where to begin?  How about trying to figure out what this blog is for, that is always a good thing to start with.</p>
<p>It is about Technical stuff.  Short technical stuff.  I want a place that I can brain dump techie ideas and brain storms.  I have other blogs where I tried to do this but this time it is different, I have a mission.</p>
<p>Not a big mission just a small one.  I want to write about the one off coding things I&#8217;m working on.  About the ideas I have had.  Review patterns and processes.</p>
<p>But mainly I just want to write.  I&#8217;ll keep the personal items out and in my personal blog so no mushie stuff.</p>
<p>For now that is all.  Come back often.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/01/06/get-this-party-started/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Need Tape</title>
		<link>http://blog.ddpruitt.net/2008/01/05/need-tape/</link>
		<comments>http://blog.ddpruitt.net/2008/01/05/need-tape/#comments</comments>
		<pubDate>Sat, 05 Jan 2008 15:05:00 +0000</pubDate>
		<dc:creator>darren</dc:creator>
				<category><![CDATA[gijoe]]></category>

		<guid isPermaLink="false">http://blog.ddpruitt.net/2008/01/05/need-tape/</guid>
		<description><![CDATA[Those are the words spoken to me by my son.  He was playing with his GI Joe (one of the fake all plastic ones) when he accidentally pulled off its head.  Oops!
This sucks because now I have to retape the head on evy time it falls off.
Of course the real GI Joe&#8217;s head [...]]]></description>
			<content:encoded><![CDATA[<p><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_b0eO9UeA-Ig/R3-hrBrDGhI/AAAAAAAAAGQ/AeHqGokHH98/s1600-h/Image_00003.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 225px; height: 169px;" src="http://1.bp.blogspot.com/_b0eO9UeA-Ig/R3-hrBrDGhI/AAAAAAAAAGQ/AeHqGokHH98/s320/Image_00003.jpg" alt="" id="BLOGGER_PHOTO_ID_5152014259290577426" border="0" /></a><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_b0eO9UeA-Ig/R3-ggRrDGgI/AAAAAAAAAGI/c9Y4CIh7U-8/s1600-h/Image_00005.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 220px; height: 165px;" src="http://2.bp.blogspot.com/_b0eO9UeA-Ig/R3-ggRrDGgI/AAAAAAAAAGI/c9Y4CIh7U-8/s320/Image_00005.jpg" alt="" id="BLOGGER_PHOTO_ID_5152012975095355906" border="0" /></a><br />Those are the words spoken to me by my son.  He was playing with his GI Joe (one of the fake all plastic ones) when he accidentally pulled off its head.  Oops!</p>
<p>This sucks because now I have to retape the head on evy time it falls off.</p>
<p>Of course the real GI Joe&#8217;s head wouldn&#8217;t have come off so easy.  Growing up we used to regularly abuse them by dropping them off of roofs, blowing them up with fire works, running them over with the car, etc. and they always survived.  These cheap plastic ripe offs, well they just suck.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.ddpruitt.net/2008/01/05/need-tape/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
