<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>The Tranxition Developer Blog</title>
	<atom:link href="http://tranxcoder.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://tranxcoder.wordpress.com</link>
	<description>Random musings from the developers at Tranxition</description>
	<lastBuildDate>Sun, 03 Jul 2011 22:43:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='tranxcoder.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>The Tranxition Developer Blog</title>
		<link>http://tranxcoder.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://tranxcoder.wordpress.com/osd.xml" title="The Tranxition Developer Blog" />
	<atom:link rel='hub' href='http://tranxcoder.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Calling GetFileInformationByHandleEx in Windows XP</title>
		<link>http://tranxcoder.wordpress.com/2010/02/02/calling-getfileinformationbyhandleex-in-windows-xp/</link>
		<comments>http://tranxcoder.wordpress.com/2010/02/02/calling-getfileinformationbyhandleex-in-windows-xp/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 22:18:12 +0000</pubDate>
		<dc:creator>ehaddan</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[fileextd.lib]]></category>
		<category><![CDATA[GetFileInformationByHandleEx]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/?p=145</guid>
		<description><![CDATA[GetFileInformationByHandleEx can provide some good information about a file from its handle, but it is only available for Window Vista and beyond.  If you still need to support Window XP, then you can try using a static library called fileextd.lib that will provide this function. The only problem is there seems to be some incompatibility [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=145&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><a href="http://msdn.microsoft.com/en-us/library/aa364953(VS.85).aspx" target="_blank">GetFileInformationByHandleEx</a> can provide some good information about a file from its handle, but it is only available for Window Vista and beyond.  If you still need to support Window XP, then you can try using a static library called fileextd.lib that will provide this function.</p>
<p>The only problem is there seems to be some incompatibility problems as described in <a href="http://social.msdn.microsoft.com/Forums/en/windowssdk/thread/78de6b2f-d01f-4394-a5c5-a4253942ae9c">this post</a>.  One of the posters recommends creating a separate DLL as a way to get around the problem, but this seems like kind of a hassle.</p>
<p>I have created this function below called GetFileInfoByHandleEx that will work from Windows XP to Windows 7(and probably Windows 2000 as well).<span id="more-145"></span> It does use some undocumented functions so I need to add a disclaimer that they could change or disappear some day, but I don&#8217;t think it is too likely.</p>
<p><pre class="brush: cpp;">
#include &lt;winternl.h&gt;
// New FILE_INFO_BY_HANDLE_CLASS value for Windows 7
#ifndef FileRemoteProtocolInfo
#define FileRemoteProtocolInfo 13
#endif
typedef NTSTATUS (WINAPI *NTQUERYINFORMATIONFILE_FUNC)(HANDLE, PIO_STATUS_BLOCK,
PVOID, ULONG, FILE_INFORMATION_CLASS);
typedef NTSTATUS (WINAPI *NTQUERYDIRECTORYFILE_FUNC)(HANDLE, HANDLE, PIO_APC_ROUTINE,
PVOID, PIO_STATUS_BLOCK, PVOID , ULONG, FILE_INFORMATION_CLASS,
BOOLEAN, PUNICODE_STRING, BOOLEAN);
typedef ULONG (WINAPI *RTLNTSTATUSTODOSERROR_FUNC)(NTSTATUS);
typedef NTSTATUS (WINAPI *NTWAITFORSINGLEOBJECT_FUNC)(HANDLE, BOOLEAN, PLARGE_INTEGER);
//
// GetFileInformationByHandleEx
//
BOOL GetFileInfoByHandleEx(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation, DWORD dwBufferSize)
{
IO_STATUS_BLOCK ioStatusBlock;
BOOL restartScan = FALSE;
int queryInformationClass = 0;
DWORD minimumSize = 8;
BOOL useDirectory = FALSE;
//
// Load ntdll.dll
//
HMODULE ntdllModule = LoadLibrary(_T(&quot;ntdll.dll&quot;));
if (ntdllModule == NULL)
{
return FALSE;
}
    //
// Get NTDLL Function Addresses
//
NTQUERYINFORMATIONFILE_FUNC pNtQueryInformationFile =
(NTQUERYINFORMATIONFILE_FUNC)GetProcAddress(ntdllModule, &quot;NtQueryInformationFile&quot;);
NTQUERYDIRECTORYFILE_FUNC pNtQueryDirectoryFile =
(NTQUERYDIRECTORYFILE_FUNC)GetProcAddress(ntdllModule, &quot;NtQueryDirectoryFile&quot;);
RTLNTSTATUSTODOSERROR_FUNC pRtlNtStatusToDosError =
(RTLNTSTATUSTODOSERROR_FUNC)GetProcAddress(ntdllModule, &quot;RtlNtStatusToDosError&quot;);
NTWAITFORSINGLEOBJECT_FUNC pNtWaitForSingleObject =
(NTWAITFORSINGLEOBJECT_FUNC)GetProcAddress(ntdllModule, &quot;NtWaitForSingleObject&quot;);
switch (FileInformationClass)
{
case FileAttributeTagInfo:
queryInformationClass = 35; // FileObjectIdInformation
break;
case FileIdBothDirectoryInfo:
case FileIdBothDirectoryRestartInfo:
queryInformationClass = 37; // FileOleDirectoryInformation
useDirectory = TRUE;
minimumSize = 0x70;
restartScan = 0;
break;
case FileRemoteProtocolInfo:
queryInformationClass = 55; // ???
minimumSize = 0x74; // sizeof(FILE_REMOTE_PROTOCOL_INFO)
break;
case FileCompressionInfo:
queryInformationClass = 28; // FileCompressionInformation
minimumSize = sizeof(FILE_COMPRESSION_INFO);
break;
case FileBasicInfo:
queryInformationClass = 4; // FileBasicInformation
minimumSize = sizeof(FILE_BASIC_INFO);
break;
case FileStandardInfo:
queryInformationClass = 5; // FileStandardInformation
minimumSize = 0x18;
break;
case FileNameInfo:
queryInformationClass = 9; // FileNameInformation
break;
case FileStreamInfo:
queryInformationClass = 22; // FileStreamInformation
minimumSize = 0x20;
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (dwBufferSize &lt; minimumSize)
{
SetLastError(ERROR_BAD_LENGTH);
return FALSE;
}
NTSTATUS status;
if (useDirectory)
{
status = pNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &amp;ioStatusBlock,
lpFileInformation, dwBufferSize,
(FILE_INFORMATION_CLASS)queryInformationClass, FALSE, NULL, restartScan);
if (status == STATUS_PENDING)
{
status = pNtWaitForSingleObject(hFile, FALSE, NULL);
if (FAILED(status))
{
SetLastError(pRtlNtStatusToDosError(status));
return FALSE;
}
status = ioStatusBlock.Status;
}
}
else
{
status = pNtQueryInformationFile(hFile, &amp;ioStatusBlock, lpFileInformation,
dwBufferSize, (FILE_INFORMATION_CLASS)queryInformationClass);
}
if (FAILED(status))
{
SetLastError(pRtlNtStatusToDosError(status));
return 0;
}
if ((FileInformationClass == FileStreamInfo) &amp;&amp; (restartScan == FALSE))
{
// STATUS_END_OF_FILE = 0xC0000011
SetLastError((pRtlNtStatusToDosError(0xC0000011)));
return FALSE;
}

return TRUE;
}
</pre></p>
<br />Filed under: <a href='http://tranxcoder.wordpress.com/category/code/'>Code</a> Tagged: <a href='http://tranxcoder.wordpress.com/tag/fileextd-lib/'>fileextd.lib</a>, <a href='http://tranxcoder.wordpress.com/tag/getfileinformationbyhandleex/'>GetFileInformationByHandleEx</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/145/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/145/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/145/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=145&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2010/02/02/calling-getfileinformationbyhandleex-in-windows-xp/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">ehaddan</media:title>
		</media:content>
	</item>
		<item>
		<title>Using Volume Shadow Services to Copy Locked Files</title>
		<link>http://tranxcoder.wordpress.com/2010/01/26/using-volume-shadow-services-to-copy-locked-files/</link>
		<comments>http://tranxcoder.wordpress.com/2010/01/26/using-volume-shadow-services-to-copy-locked-files/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 17:47:03 +0000</pubDate>
		<dc:creator>ehaddan</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[0x80042302]]></category>
		<category><![CDATA[AddToSnapshotSet]]></category>
		<category><![CDATA[CreateVssBackupComponents]]></category>
		<category><![CDATA[DoSnapshotSet]]></category>
		<category><![CDATA[GatherWriterMetadata]]></category>
		<category><![CDATA[GetSnapshotProperties]]></category>
		<category><![CDATA[InitializeForBackup]]></category>
		<category><![CDATA[IVssBackupComponents]]></category>
		<category><![CDATA[PrepareForBackup]]></category>
		<category><![CDATA[SetBackupState]]></category>
		<category><![CDATA[StartSnapshotSet]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/?p=140</guid>
		<description><![CDATA[I recently spent time investigating the Volume Shadow Copy Service(VSS) and found that it was very confusing.  I just needed to be able to copy files that were locked by other applications and VSS seemed like the way to go. As I was starting out trying to get my sample working, I ran into a couple of problems.  [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=140&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I recently spent time investigating the <a href="http://msdn.microsoft.com/en-us/library/aa384649(VS.85).aspx">Volume Shadow Copy Service(VSS)</a> and found that it was very confusing.  I just needed to be able to copy files that were locked by other applications and VSS seemed like the way to go.</p>
<p><span id="more-140"></span>As I was starting out trying to get my sample working, I ran into a couple of problems.  The problems occurred when I would call the InitializeForBackup function from the IVssBackupComponent interface.  It would return the value 0&#215;80042302.  When I looked in vsserror.h, that value was skipped:</p>
<p><code>//<br />
// MessageId: VSS_E_BAD_STATE<br />
//<br />
// MessageText:<br />
//<br />
// A function call was made when the object was in an incorrect state<br />
// for that function<br />
//<br />
#define VSS_E_BAD_STATE ((HRESULT)0x80042301L)</code></p>
<p><code>//<br />
// MessageId: VSS_E_PROVIDER_ALREADY_REGISTERED<br />
//<br />
// MessageText:<br />
//<br />
// The provider has already been registered.<br />
//<br />
#define VSS_E_PROVIDER_ALREADY_REGISTERED ((HRESULT)0x80042303L)</code></p>
<p>I discovered later that the value was defined in V7 of the SDK and it is defined as VSS_E_UNEXPECTED and it simply meant to check the application event logs for more information.</p>
<p>So I checked the Application Log and was getting the following error.</p>
<p><code>Volume Shadow Copy Service error: Unexpected error calling routine CoCreateInstance. hr = 0x800401f0, CoInitialize has not been called.<br />
.<br />
Operation:<br />
Initialize For Backup<br />
</code><br />
I did some searches and eventually found <a href="http://forums.techarena.in/small-business-server/800059.htm">a forum post</a> that said to make sure that the &#8220;Volume Shadow Copy&#8221;, &#8220;COM+ System Application&#8221;, and the &#8220;Distributed Transaction Coordinator&#8221; services were running.  My &#8220;COM+ System Application&#8221; service was not running, so I started it and it fixed that problem.</p>
<p>But then another error occurred:</p>
<p><code>Volume Shadow Copy Service error: A critical component required by the Volume Shadow Copy service is not registered. This might happened if an error occurred during Windows setup or during installation of a Shadow Copy provider. The error returned from CoCreateInstance on class with CLSID {e579ab5f-1cc4-44b4-bed9-de0991ff0623} and Name IVssCoordinatorEx2 is [0x80040154, Class not registered].<br />
Operation:<br />
Instantiating VSS server</code></p>
<p>I figured out that this was being caused because I was making my application a 32-bit application running on a 64-bit OS.  The documentation specifically says &#8220;All 32-bit VSS applications (requesters, providers, and writers) must run as native 32-bit or 64-bit applications. Running them under WOW64 is not supported.&#8221; and this is what happens when you ignore it.</p>
<p>So I was about 90% of the way finished, but the last part of actually doing the file copy was a little unclear, so after a little bit of searching, I found the VShadow sample project in the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0B4F56E4-0CCC-4626-826A-ED2C4C95C871&amp;displaylang=en">Volume Shadow Copy Service SDK 7.2</a> which seemed like it would be perfect for my needs.  Well, it&#8217;s a very powerful tool, but it  really wasn&#8217;t that clear on how to use this utility to copy a file either.</p>
<p>I felt like I was getting very close!</p>
<p>After a little more searching, I found <a href="http://blogs.msdn.com/adioltean/archive/2005/01/05/346793.aspx">SCRIPT RECIPE OF THE WEEK: HOW TO COPY AN OPENED FILE</a> which gave me the information needed on how to call VShadow, along with other cool features like how to recursively call your script.  It worked, but there were still a few problems like not being able to use it from a long file path with spaces and it also wouldn&#8217;t copy hidden files.</p>
<p>But based on how this script called VShadow, I was able to figure out my missing piece and finished this sample.</p>
<p>So, in a nutshell, this is a sample of how to copy a single locked file:</p>
<p>LockeFileCopy.cpp</p>
<p><pre class="brush: cpp;">

#include &lt;stdio.h&gt;
#include &lt;tchar.h&gt;
#include &lt;shlwapi.h&gt;
#include &lt;vss.h&gt;
#include &lt;vswriter.h&gt;
#include &lt;vsbackup.h&gt;

int _tmain(int argc, _TCHAR* argv[])
{
int returnValue = 1;
if (argc != 3)
{
printf(&quot;Usage: LockedFileCopy.exe sourcefile destinationfile\n&quot;);
return 1;
}
TCHAR sourceFile[_MAX_PATH] = {0};
LPTSTR destinationFile = argv[2];

//
// Create an absolute path if it is relative
//
_tcscpy(sourceFile, argv[1]);
if (PathIsRelative(sourceFile))
{
::PathFindFileName(sourceFile);
}

if (_taccess(sourceFile,0) != 0)
{
_tprintf(_T(&quot;\&quot;%s\&quot; does not exist!\n&quot;), argv[1]);
return 1;
}

if (CoInitialize(NULL) != S_OK)
{
printf(&quot;CoInitialize failed!\n&quot;);
return 1;
}

//
// Create the IVssBackupComponents Interface
//
IVssBackupComponents *pBackup = NULL;
HRESULT result = CreateVssBackupComponents(&amp;pBackup);
if (result == S_OK)
{
//
// Initialize for backup
//
result = pBackup-&gt;InitializeForBackup();&lt;/code&gt;

if (result == S_OK)
{
//
// Prompts each writer to send the metadata they have collected
//
IVssAsync *pAsync = NULL;
result = pBackup-&gt;GatherWriterMetadata(&amp;pAsync);
if (result == S_OK)
{
printf(&quot;Gathering metadata from writers...\n&quot;);
result = pAsync-&gt;Wait();
if (result == S_OK)
{
//
// Creates a new, empty shadow copy set
//
VSS_ID snapshotSetId;
result = pBackup-&gt;StartSnapshotSet(&amp;snapshotSetId);
if (result == S_OK)
{
//
// Add Volume to the shadow copy set
//
WCHAR volumeName[4] = {sourceFile[0], _T(':'), _T(&quot;\\&quot;)};
wprintf(L&quot;Adding %s volume to snapshot set...\n&quot;, volumeName);
result = pBackup-&gt;AddToSnapshotSet(volumeName, GUID_NULL, &amp;snapshotSetId);
if (result == S_OK)
{
//
// Configure the backup operation for Copy with no backup history
//
result = pBackup-&gt;SetBackupState(false, false, VSS_BT_COPY);
if (result == S_OK)
{
//
// Make VSS generate a PrepareForBackup event
//
IVssAsync* pPrepare = NULL;
result = pBackup-&gt;PrepareForBackup(&amp;pPrepare);
if (result == S_OK)
{
printf(&quot;Preparing for backup...\n&quot;);
result = pPrepare-&gt;Wait();
if (result == S_OK)
{
//
// Commit all snapshots in this set
//
IVssAsync* pDoShadowCopy = NULL;
result = pBackup-&gt;DoSnapshotSet(&amp;pDoShadowCopy);
if (result == S_OK)
{
printf(&quot;Taking snapshots...\n&quot;);
result = pDoShadowCopy-&gt;Wait();
if (result == S_OK)
{
//
// Get the snapshot device object from the properties
//
VSS_SNAPSHOT_PROP snapshotProp = {0};
result = pBackup-&gt;GetSnapshotProperties(snapshotSetId, &amp;snapshotProp);
if (result == S_OK)
{
//
// Create the source path by using the volume specified in
// m_pwszSnapshotDeviceObject and appending the path of
// the source file (minus the drive letter)
//
int sourceLength = wcslen(snapshotProp.m_pwszSnapshotDeviceObject) +
_tcslen(sourceFile);
LPTSTR sourceSnapshotFile = new TCHAR[sourceLength];
_tcscpy_s(sourceSnapshotFile, sourceLength,
snapshotProp.m_pwszSnapshotDeviceObject);
_tcscat_s(sourceSnapshotFile, sourceLength, &amp;sourceFile[2]);&lt;/code&gt;

//
// Copy the file from the snapshot device object
//
if (!::CopyFile(sourceSnapshotFile, destinationFile, FALSE))
{
DWORD lastError = GetLastError();
printf(&quot;Failed to copy file - Error: %d\n&quot;, lastError);
}
else
{
printf(&quot;Successfully copied file!\n&quot;);
returnValue = 0;
}
delete [] sourceSnapshotFile;&lt;/code&gt;

//
// Cleanup properties
//
VssFreeSnapshotProperties(&amp;snapshotProp);
}
}
pDoShadowCopy-&gt;Release();
}
}
pPrepare-&gt;Release();
}
}
}
//
// Delete the snapshot
//
LONG deletedSnapshots = 0;
VSS_ID nonDeletedSnapshotId;
result = pBackup-&gt;DeleteSnapshots(snapshotSetId, VSS_OBJECT_SNAPSHOT,
TRUE, &amp;deletedSnapshots, &amp;nonDeletedSnapshotId);
}
}
pAsync-&gt;Release();
}
}
pBackup-&gt;Release();
}
return returnValue;
}

</pre></p>
<br />Posted in Code Tagged: 0x80042302, AddToSnapshotSet, CreateVssBackupComponents, DoSnapshotSet, GatherWriterMetadata, GetSnapshotProperties, InitializeForBackup, IVssBackupComponents, PrepareForBackup, SetBackupState, StartSnapshotSet <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/140/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/140/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/140/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=140&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2010/01/26/using-volume-shadow-services-to-copy-locked-files/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">ehaddan</media:title>
		</media:content>
	</item>
		<item>
		<title>Team Build IsA MSBuild?</title>
		<link>http://tranxcoder.wordpress.com/2009/03/24/team-build-isa-msbuild/</link>
		<comments>http://tranxcoder.wordpress.com/2009/03/24/team-build-isa-msbuild/#comments</comments>
		<pubDate>Tue, 24 Mar 2009 01:23:28 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[MSBuild]]></category>
		<category><![CDATA[Team Build]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2009/03/24/team-build-isa-msbuild/</guid>
		<description><![CDATA[I had one of those Aha! moments this weekend. You know, the ones that Oprah is always talking about (not that I watch, it just happens to be on sometimes when I’m in the room…) It turns that somehow in my dealings with Team Foundation Build (i.e. “Team Build”) I had always maintained this subconscious [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=125&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I had one of those Aha! moments this weekend. You know, the ones that <a title="oprah.com: Aha! Moments" href="http://www.oprah.com/article/omagazine/aha/rys_omag_200603_aha" target="_blank" rel="nofollow">Oprah is always talking about</a> (not that I watch, it just happens to be on sometimes when I’m in the room…) It turns that somehow in my dealings with <a title="msdn.microsoft.com: Team Foundation Build Overview" href="http://msdn.microsoft.com/en-us/library/ms181710.aspx" target="_blank">Team Foundation Build</a> (i.e. “Team Build”) I had always maintained this subconscious assumption that Team Build was really just MSBuild++, or rather, a proper superset of the functionality that MSBuild provides. I probably wouldn’t even have balked had someone shown me a UML diagram like this:</p>
<p align="center"><a href="http://tranxcoder.files.wordpress.com/2009/03/image.png"><img title="image" style="display:inline;border-width:0;" height="92" alt="image" src="http://tranxcoder.files.wordpress.com/2009/03/image-thumb.png?w=209&#038;h=92" width="209" border="0" /></a></p>
<p>The assertion there being that Team Build is just a realization of MSBuild, extended to work in a broader, team environment. A follow-on assertion (that certainly I made) is that the team who created Team Build started with MSBuild as a basis and worked out. My “Aha! Moment” was realizing that in fact it is not an IsA relationship at all, but rather a pure HasA relationship:</p>
<p> <span id="more-125"></span>
</p>
<p align="center"><a href="http://tranxcoder.files.wordpress.com/2009/03/image1.png"><img title="image" style="display:inline;border-width:0;" height="92" alt="image" src="http://tranxcoder.files.wordpress.com/2009/03/image-thumb1.png?w=194&#038;h=92" width="194" border="0" /></a> </p>
<p>Internally, Team Build <em>uses</em> MSBuild, and as such, to perform many of its common tasks it <em>depends on</em> MSBuild, but Team Build is most certainly <strong>not</strong> MSBuild.</p>
<p>I’m sure after reading this most people are probably thinking two things:</p>
<ol>
<li>Duh! </li>
<li>So what? </li>
</ol>
<p>As for your first thought; hey, cut me some slack. I never claimed to be the sharpest tool in the shed. That said, odds are I’m not the first person to incorrectly assume a more intimate relationship between Team Build and MSBuild than what actually exists.</p>
<p>To address your second thought; let’s look at this from the other perspective. What assumptions might you hold about the capabilities of MSBuild that may actually be capabilities inherent to Team Build which have no corollary in the context of MSBuild. Specifically for me this showed up as support for building (and controlling the build process of) “solutions”.</p>
<p>If you’ve done any work customizing a MSBuild project’s build process, the ability to override build properties and targets has probably been very useful. If not, then let me edify you now:</p>
<p>You have the ability to override build properties and targets in your MSBuild projects (which includes C# (.csproj), VB.NET (.vbproj), ASP.NET Web Deployment Projects (.wdproj) , et al.) In fact, if you crack open the .csproj file for any of your VS2008 C# projects, you’ll see the following markup at the bottom:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<pre style="margin:0;"><span style="color:blue;">&lt;!--</span><span style="color:green;"> To modify your build process, add your task inside one of the targets below and uncomment it.</span><span style="color:green;"> Other similar extension points exist, see Microsoft.Common.targets.</span></pre>
<pre style="margin:0;"><span style="color:green;">&lt;Target Name=&quot;BeforeBuild&quot;&gt;</span></pre>
<pre style="margin:0;"><span style="color:green;">&lt;/Target&gt;</span></pre>
<pre style="margin:0;"><span style="color:green;">&lt;Target Name=&quot;AfterBuild&quot;&gt;</span></pre>
<pre style="margin:0;"><span style="color:green;">&lt;/Target&gt;</span></pre>
<pre style="margin:0;"><span style="color:blue;">--&gt;</span></pre>
</div>
<p>If your Team Build experience is at all like mine then you’re more than a little familiar with both the Target element and the nomenclature of <strong>Before</strong>Target/<strong>After</strong>Target. The idea there is pretty straightforward, rather than using the clunky old “PostBuild Steps” from the days of yore (which you can still do, but why?) they are explicitly inviting you to interact directly with MSBuild in altering your build steps. This has been <a title="realfiction.net: Don&#39;t be afraid of your csproj-Files (I): Embracing the idea" href="http://realfiction.net/?q=node/162" target="_blank">written about</a> quite a bit and can be very handy for simplifying the lives of current and future developers on a project. One thing we like to do on my current project is to ensure that any actions normally taken by our installer are automatically applied after each build on a development machine. For instance:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<pre style="margin:0;"><span style="color:blue;">&lt;</span><span style="color:#a31515;">Target</span><span style="color:blue;"> </span><span style="color:red;">Name</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">AfterBuild</span>&quot;<span style="color:blue;"> </span><span style="color:red;">Condition</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">$(DevEnvDir) != '*Undefined*'</span>&quot;<span style="color:blue;">&gt;</span></pre>
<pre style="margin:0;"><span style="color:blue;">&#160; &lt;</span><span style="color:#a31515;">Message</span><span style="color:blue;"> </span><span style="color:red;">Text</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">Copying My targets file</span>&quot;<span style="color:blue;"> /&gt;</span></pre>
<pre style="margin:0;"><span style="color:blue;">&#160; &lt;</span><span style="color:#a31515;">Copy</span><span style="color:blue;"> </span><span style="color:red;">SourceFiles</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">$(ProjectDir)My.targets</span>&quot;<span style="color:blue;"> </span><span style="color:red;">DestinationFolder</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">$(MSBuildExtensionsPath)\My\</span>&quot;<span style="color:blue;"> </span><span style="color:red;">ContinueOnError</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">false</span>&quot;<span style="color:blue;"> </span><span style="color:red;">SkipUnchangedFiles</span><span style="color:blue;">=</span>&quot;<span style="color:blue;">false</span>&quot;<span style="color:blue;"> /&gt;</span></pre>
<pre style="margin:0;"><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Target</span><span style="color:blue;">&gt;</span></pre>
</div>
<p>That target will copy the “My.targets” file from the project’s source directory to the system configured path for MSBuild extensions after each successful build. That may not be very useful in your situation, but for our project it is a major developer productivity boon.</p>
<p>Let’s say, however, that you wanted some particular bit of functionality to execute after each successful Solution build. How would you go about it? Well, I can tell you one thing that will not work – adding solution-related targets to your .csproj file. One reason may seem obvious, each project is build individually by MSBuild. Therefore, when a particular project is building it really has no information about the overall status of the outer build. The more important reason, however, is that generally speaking, your solutions are not built by MSBuild.</p>
<p>Now if you really want to you can call msbuild.exe from the command-line to build your solution. And if your solution consists only of projects whose type is one of the few project types directly supported by MSBuild, then MSBuild can build your solution. However, the vast majority of Visual Studio solutions will never be built by MSBuild. True story.</p>
<p>So what does build them? More often than not, the build is managed by Visual Studio itself. Other tools that you may run into which can directly build solutions are <a href="http://nant.sourceforge.net/release/0.85-rc1/help/tasks/solution.html" target="_blank">NAnt</a> and of course Team Build, which I’ll get to shortly.</p>
<p>If you look in your solution file (.sln) you’ll see the first few lines looks like this:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<pre style="margin:0;">Microsoft Visual Studio Solution File, Format Version 10.00</pre>
<pre style="margin:0;"># Visual Studio 2008</pre>
</div>
<p>Notice that A) that is obviously not XML syntax and B) it’s pretty specific about which application this file’s format belongs to. In other words, this is not an MSBuild file, this is a Visual Studio file. When you execute the <img title="image" style="display:inline;border-width:0;" height="22" alt="image" src="http://tranxcoder.files.wordpress.com/2009/03/image2.png?w=208&#038;h=22" width="208" border="0" /> command, Visual Studio (not MSBuild) runs the show. It decides which projects should build, when they should build and which build targets to execute, and it decides how and where to log any output and where to drop the output files. It also, for example, knows that Visual C++ projects should build using VCBuild whereas C# projects should build using MSBuild.</p>
<p>Alright, back to Team Build. How does Team Build know what to do with a .sln file that is specific to Visual Studio? The team behind Team Build coded support for that (external) file format into their system and decided what to do with them. Generally speaking, they don’t do much with them besides parsing out the configured projects and their supported build platform and configuration pairs. After that, Team Build handles solution building just like it does project building – it has a set of predefined solution targets that execute in a predefined order (all of which is overridable) that ultimately calls a task they wrote named <a title="msdn.microsoft.com: MSBuild Task" href="http://msdn.microsoft.com/en-us/library/z7f65y0d.aspx" target="_blank">MSBuild</a> and passes in the solution file’s path along with the configuration and platform to build as well as a bunch of additional properties and metadata. What’s important to note here is that Team Build’s MSBuild Task does execute MSBuild, it just does so in an over-controlling-boss fashion. One of the side-effects, however, is that Team Build does not support building solutions which contain non-MSBuild project types. Rather than failing when it encounters those projects, MSBuild instead will skip them and build the project types it does support (I’m still in the process of validating that statement.)</p>
<p>MSDN has a walkthrough on <a title="msdn.microsoft.com" href="http://msdn.microsoft.com/en-us/library/ms404859.aspx" target="_blank">configuring Team Build to build a Visual Studio Setup Project</a> (one of the project types supported by Visual Studio but not supported by MSBuild.) The meat of the walkthrough is really near the end:</p>
<pre class="csharpcode"><span class="kwrd">&lt;</span><span class="html">Target</span> <span class="attr">Name</span><span class="kwrd">=&quot;AfterCompile&quot;</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">Exec</span> <span class="attr">Command</span><span class="kwrd">=&quot;&amp;quot;$(ProgramFiles)\Microsoft Visual Studio 9.0\Common7\IDE\devenv&amp;quot; &amp;quot;$(SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\HelloWorldTestInstaller.vdproj&amp;quot; /Build &amp;quot;Debug|Any CPU&amp;quot;&quot;</span><span class="kwrd">/&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">Copy</span> <span class="attr">SourceFiles</span><span class="kwrd">=&quot;$(SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\Debug\HelloWorldTestInstaller.msi; SolutionRoot)\HelloWorldTest\HelloWorldTestInstaller\Debug\setup.exe&quot;</span> <span class="attr">DestinationFolder</span><span class="kwrd">=&quot;$(OutDir)&quot;</span> <span class="kwrd">/&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">Target</span><span class="kwrd">&gt;</span></pre>
<p>This target will be called once the compilation chain is complete (all solution and project configurations have been compiled.) What does it do? Because Visual Studio knows how to build Setup projects and MSBuild does not, it actually calls out to devenv.exe (the Visual Studio executable) passing it “/build ‘Debug|Any CPU’” and the path to the project file to build.</p>
<p>So where does all this knowledge of Visual Studio, MSBuild, and Team Build leave us? Well for me it has created a bit of a quandary and at this point I’m still not sure the best way to resolve it. I need to find a way to interact with the solution build sequence of Visual Studio (and probably Team Build at some point) such that I can execute some custom validation on a fully built solution, rather than on individual projects. The only thing I can be 100% certain of is that MSBuild will have little or no direct involvement.</p>
<p>For now that’s where I leave this post. I have a feeling my follow-up will involve Visual Studio eXtensibility hooks convoluted enough to make grown men weep. But until I know that for sure, I’ll just keep smiling while I think about kittens and bunnies.</p>
<br />Posted in Code, Tools Tagged: MSBuild, Team Build, Visual Studio <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/125/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/125/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/125/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=125&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2009/03/24/team-build-isa-msbuild/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2009/03/image-thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2009/03/image-thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2009/03/image2.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Could you be a Tranxcoder?</title>
		<link>http://tranxcoder.wordpress.com/2008/11/20/could-you-be-a-tranxcoder/</link>
		<comments>http://tranxcoder.wordpress.com/2008/11/20/could-you-be-a-tranxcoder/#comments</comments>
		<pubDate>Thu, 20 Nov 2008 08:15:14 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Jobs]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/11/20/could-you-be-a-tranxcoder/</guid>
		<description><![CDATA[We&#8217;re hiring. No, really, we are. I realize you know three developers who either recently lost their jobs or are fairly confident it&#8217;s about to happen, but despite the downturn, we are hiring. Even more striking is that these are new positions &#8211; not replacements! That&#8217;s right, on the cusp of what some are predicting [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=101&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>We&#8217;re hiring. No, really, we are. I realize you know three developers who either recently lost their jobs or are fairly confident it&#8217;s about to happen, but despite the downturn, we are hiring. Even more striking is that these are <em><strong>new</strong></em> positions &#8211; not replacements! That&#8217;s right, on the cusp of what some are predicting will be the worst U.S. economic slump since The Great Depression, we are growing our engineering team. Have I made this clear yet?</p>
<p>Why dwell on economic troubles in a job post? Because sometimes we hear that good developers hesitate to look at small companies because they want &#8220;stability&#8221;. Well I would just like to point out that while most of the major corporations in the country are gearing up for hiring freezes, pay cuts, lay offs, and who knows what else; our tiny little company is as strong as I&#8217;ve ever seen it and shows no signs of slowing. Come get your stability while it&#8217;s hot.</p>
</p>
<p><span id="more-101"></span>
</p>
<p>As for what we&#8217;re looking for, I&#8217;m just going to <a title="Careers at Tranxition" href="http://www.tranxition.com/careers.html">republish</a> our standard job description. If you are at all interested, please email <a href="mailto:hiring@tranxition.com">hiring@tranxition.com</a> with your <em>half-page résumé</em>. What? You don&#8217;t have one of those ready to send? That&#8217;s the whole point &#8230; we don&#8217;t hire by the same standards and methods that Intel does, so you shouldn&#8217;t expect the same résumé will work with us that works with them. Take a few minutes and show us why we should hire <em>you</em>, not your bullet points. Of course if you really can&#8217;t do it, we&#8217;ll take your 3 page list of bullet points as well. We just won&#8217;t like it.</p>
<p><strong>Title:<br /></strong>Senior Software Engineer, Full-time employee</p>
<p><strong>The Hook:<br /></strong>Superstars wanted!</p>
<p>Do you have the chops to develop bleeding edge software on leading edge platforms? Do you have a history of getting things done and a demonstrable aptitude for all things software? Do you despise buzzwords like self-motivated and self-starter, but embody their ideals anyway? If so, then you should join our dev team.</p>
<p><strong>The Team:<br /></strong>At Tranxition, our engineers eat and sleep software. We do our best coding in the bathroom and we’re not afraid to admit it. No algorithm is perfect and no architecture is complete, but we know when to call it good enough because perfection is a dream and profitability means we get to come back tomorrow.</p>
<p>We thrive on natural talent and we constantly nurture our talented. We don’t ask management if we can receive training; management asks us which training we want to receive. New technology, old technology, we do it all and we do it well.</p>
<p>Iterative development is our core because it works. Unit testing is not optional because working software is not optional. QA is an integral part of our team for the same reason. We don’t do pair programming because sometimes – we just need to sleep in. Or work from home. Or put in a twelve hour day because this problem needs to be solved and we want to solve it, today!</p>
<p><strong>The Profile:<br /></strong>Our primary concern is to find people smarter than us to join our team. That said, we have a specific skill set that we would love to match and those who do may find themselves at the front of the pack:</p>
<p>· Real-world advanced .NET experience<br />· Full SDLC (specification through maintenance) experience<br />· Iterative development experience<br />· Commercial software experience<br />· Experience designing and implementing web services<br />· SQL Server experience<br />· Active Directory and Group Policy experience<br />· WMI development experience<br />· Unmanaged C/C++ development experience<br />· Experience with Team Foundation Server, MSBuild (<b><i>or </i></b>NAnt, Ant), and MSTest (<b><i>or </i></b>NUnit, MbUnit, xUnit.net, JUnit)<br />· WPF, LINQ and PowerShell aren’t foreign concepts<br />· Reference shelf includes books with “Internals” in the title<br />· Indigo equals WCF and WinFS is the greatest lost feature since Microsoft Bob</p>
<br />Posted in Jobs  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/101/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/101/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/101/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=101&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/11/20/could-you-be-a-tranxcoder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>
	</item>
		<item>
		<title>Customizing &#8220;lookful&#8221; WPF controls &#8211; Take 2</title>
		<link>http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/</link>
		<comments>http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/#comments</comments>
		<pubDate>Sun, 12 Oct 2008 09:56:59 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/</guid>
		<description><![CDATA[Last week I posted a technique for customizing controls in WPF that don&#8217;t offer a replaceable ControlTemplate &#8211; I described them as &#8220;lookful&#8221; controls because their behavior and appearance are tied in with their functionality. My approach involved creating a custom control that derives from the one being targeted. That solution has some significant downsides, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=92&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Last week I <a href="http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/">posted a technique</a> for customizing controls in WPF that don&#8217;t offer a replaceable ControlTemplate &#8211; I described them as &#8220;lookful&#8221; controls because their behavior and appearance are tied in with their functionality. My approach involved creating a custom control that derives from the one being targeted. That solution has some significant downsides, though, including that if the control is part of another (composition) then you have to modify the parent control to tell it to use your new custom control as a child &#8211; it works in most cases, it&#8217;s just not ideal. I figured someone might call me out on it eventually and, sure enough, the day I posted it fellow WPF&#8217;er &#8220;John&#8221; ruminated in a comment about using attached properties to accomplish the task instead. That got my wheels turning and I decided to put together a solution that, frankly, <a title="Code Smell" href="http://en.wikipedia.org/wiki/Code_smell" target="_blank">doesn&#8217;t stink</a>&#8230;</p>
<p><span id="more-92"></span></p>
<p>The control I covered was the TextBlock, and the customizations I made involved adding a dependency property called IsTextTrimmed to my derived control which indicates if the text is being trimmed (clipped with ellipses appended). This time I&#8217;ll tackle that same issue, but do it in a way that doesn&#8217;t require custom controls, is easy to use, and is flexible enough to support any number of additional customizations.</p>
<p>At the end of this post there is a link to a solution which contains the TextBlockService assembly and a Sample WpfApplication that demonstrates its usage. As with everything we post on The Tranxition Developer Blog, feel free to use it however you wish, ask questions, or suggest alternatives. Rather than cover <em>how</em> all of this works (there are a lot of WPF concepts involved), I&#8217;m just going to lay out the key bits and then explain a little about <em>why</em> I made certain design and implementation decisions.</p>
<p>All of the functionality resides in the TextBlockService assembly with most of the logic in TextBlockService.cs. That file holds a single public class called TextBlockService which serves as an attached property provider for two properties, the critical one being TextBlockService.IsTextTrimmed.</p>
<p>The attached properties mechanism is one of the coolest (and least intuitive) things about WPF. In this case, I&#8217;m bucking the norm which involves backing all attached properties with corresponding dependency properties. As a result, my class doesn&#8217;t need to implement any dependency property requirements and also need not derive from the DependencyObject class. It seems odd at first, but the instance values for these properties are maintained entirely by the framework, with no help from my class.</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">readonly</span> <span style="color:#a65300;">DependencyPropertyKey</span> <span style="color:maroon;">IsTextTrimmedKey</span> = <span style="color:#a65300;">DependencyProperty</span>.<span style="color:maroon;">RegisterAttachedReadOnly</span>(</p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span>     <span style="background:#ffffe6;">&#8220;IsTextTrimmed&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span>     <span style="color:navy;">typeof</span>( <span style="color:navy;">bool</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span>     <span style="color:navy;">typeof</span>( <span style="color:#a65300;">TextBlockService</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span>     <span style="color:navy;">new</span> <span style="color:#a65300;">PropertyMetadata</span>( <span style="color:navy;">false</span> ) );</p>
</div>
<p>That code fragment is what registers my attached property as &#8220;TextBlockService.IsTextTrimmed&#8221; in XAML, sets it type to bool, and sets the default value to false. Since this property can&#8217;t logically be &#8220;set&#8221; by a consumer, it&#8217;s registered as read-only which means instead of returning a DependencyProperty object, it returns a DependencyPropertyKey. That key is used to retrieve a special type of DependencyProperty object:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">readonly</span> <span style="color:#a65300;">DependencyProperty</span> <span style="color:maroon;">IsTextTrimmedProperty</span> = <span style="color:maroon;">IsTextTrimmedKey</span>.<span style="color:maroon;">DependencyProperty</span>;</p>
</div>
<p>Which is used when retrieving the current value:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> [<span style="color:#a65300;">AttachedPropertyBrowsableForType</span>( <span style="color:navy;">typeof</span>( <span style="color:#a65300;">TextBlock</span> ) )]</p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:#2b91af;">Boolean</span> <span style="color:maroon;">GetIsTextTrimmed</span>( <span style="color:#a65300;">TextBlock</span> <span style="color:maroon;">target</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span>     <span style="color:navy;">return</span> (<span style="color:#2b91af;">Boolean</span>) <span style="color:maroon;">target</span>.<span style="color:maroon;">GetValue</span>( <span style="color:maroon;">IsTextTrimmedProperty</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span> }</p>
</div>
<p>This property (IsTextTrimmed) only makes sense when attached directly to a TextBlock so I used AttachedPropertyBrowsableForType to restrict designers to only displaying it as an attribute on TextBlock elements. This doesn&#8217;t actually prevent users from trying to attach it to other element types, but it won&#8217;t show as an available option in the IDE. In addition I made the parameter type TextBlock on GetIsTextTrimmed where normally for attached properties this will be something much more generic like DependencyObject or UIElement, etc.</p>
<p>With that bit of code we&#8217;ve created a full fledged read-only property that can be attached to any TextBlock control. However, we lack any means to actually <em>set</em> the value (besides its default).</p>
<p>I simply adapted a function that calculates the current trimmed state for any given TextBlock by adding a bit of logic at the top to retrieve the present IsTextTrimmed value if the TextBlock is not in a state where it can be evaluated:</p>
<p><pre class="brush: csharp;">private static bool CalculateIsTextTrimmed( TextBlock textBlock )
{
    if ( !textBlock.IsArrangeValid )
    {
        return GetIsTextTrimmed( textBlock );
    }

    Typeface typeface = new Typeface(
        textBlock.FontFamily,
        textBlock.FontStyle,
        textBlock.FontWeight,
        textBlock.FontStretch );

    // FormattedText is used to measure the whole width of the text held up by TextBlock container
    FormattedText formattedText = new FormattedText(
        textBlock.Text,
        System.Threading.Thread.CurrentThread.CurrentCulture,
        textBlock.FlowDirection,
        typeface,
        textBlock.FontSize,
        textBlock.Foreground );

    formattedText.MaxTextWidth = textBlock.ActualWidth;

    // When the maximum text width of the FormattedText instance is set to the actual
    // width of the textBlock, if the textBlock is being trimmed to fit then the formatted
    // text will report a larger height than the textBlock. Should work whether the
    // textBlock is single or multi-line.
    return ( formattedText.Height &gt; textBlock.ActualHeight );
}
</pre></p>
<address><em>(Note that I&#8217;m using a version of the <a title="How to judge text block is trimming with ..." href="http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4406e828-bee1-49fb-a26a-3128a18e0595/" target="_blank">alternate trimmed state algorithm</a> with input from Jean-Marie Pirelli that was referred to by John in the comment on my original blog entry. This algorithm may have issues when certain transforms are applied, but it has much better maintainability than my original reflection-based approach.)</em></address>
<p>Now that the state can be determined, we need something to trigger that determination. Meet <a title="EventManager.RegisterClassHandler Method (System.Windows)" href="http://msdn.microsoft.com/en-us/library/system.windows.eventmanager.registerclasshandler.aspx" target="_blank">EventManager.RegisterClassHandler</a>:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:navy;">static</span> <span style="color:maroon;">TextBlockService</span>()</p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span>     <span style="color:green;">// Register for the SizeChanged event on all TextBlocks, even if the event was handled.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span>     <span style="color:#a65300;">EventManager</span>.<span style="color:maroon;">RegisterClassHandler</span>(</p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span>         <span style="color:navy;">typeof</span>( <span style="color:#a65300;">TextBlock</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  6</span>         <span style="color:#a65300;">FrameworkElement</span>.<span style="color:maroon;">SizeChangedEvent</span>,</p>
<p style="margin:0;"><span style="background:gray;color:white;">  7</span>         <span style="color:navy;">new</span> <span style="color:#2b91af;">SizeChangedEventHandler</span>( <span style="color:maroon;">OnTextBlockSizeChanged</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  8</span>         <span style="color:navy;">true</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">  9</span> }</p>
</div>
<p>This code in the service class&#8217;s static constructor causes an event handler for the SizeChangedEvent (from FrameworkElement) to be registered for every instance of the TextBlock class. Additionally it allows me to specify that the event handler should be called even if the event has already been marked &#8220;handled&#8221; by a previous handler. I&#8217;m greedy like that. The actual event handler is fairly straight forward, just checking to make sure trimming is even possible before bothering to evaluate it:</p>
<div style="font-family:Consolas;font-size:10pt;color:black;background:#f8f8f8;">
<p style="margin:0;"><span style="color:white;background:gray;">  1</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">void</span> <span style="color:maroon;">OnTextBlockSizeChanged</span>( <span style="color:navy;">object</span> <span style="color:maroon;">sender</span>, <span style="color:#a65300;">SizeChangedEventArgs</span> <span style="color:maroon;">e</span> )</p>
<p style="margin:0;"><span style="color:white;background:gray;">  2</span> {</p>
<p style="margin:0;"><span style="color:white;background:gray;">  3</span>     <span style="color:navy;">var</span> <span style="color:maroon;">textBlock</span> = <span style="color:maroon;">sender</span> <span style="color:navy;">as</span> <span style="color:#a65300;">TextBlock</span>;</p>
<p style="margin:0;"><span style="color:white;background:gray;">  4</span>     <span style="color:navy;">if</span> ( <span style="color:navy;">null</span> == <span style="color:maroon;">textBlock</span> )</p>
<p style="margin:0;"><span style="color:white;background:gray;">  5</span>     {</p>
<p style="margin:0;"><span style="color:white;background:gray;">  6</span>         <span style="color:navy;">return</span>;</p>
<p style="margin:0;"><span style="color:white;background:gray;">  7</span>     }</p>
<p style="margin:0;"><span style="color:white;background:gray;">  8</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;">  9</span>     <span style="color:navy;">if</span> ( <span style="color:#2b91af;">TextTrimming</span>.<span style="color:maroon;">None</span> == <span style="color:maroon;">textBlock</span>.<span style="color:maroon;">TextTrimming</span> )</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 10</span>     {</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 11</span>         <span style="color:maroon;">SetIsTextTrimmed</span>( <span style="color:maroon;">textBlock</span>, <span style="color:navy;">false</span> );</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 12</span>     }</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 13</span>     <span style="color:navy;">else</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 14</span>     {</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 15</span>         <span style="color:maroon;">SetIsTextTrimmed</span>( <span style="color:maroon;">textBlock</span>, <span style="color:maroon;">CalculateIsTextTrimmed</span>( <span style="color:maroon;">textBlock</span> ) );</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 16</span>     }</p>
<p style="margin:0;"><span style="color:white;background:gray;"> 17</span> }</p>
</div>
<p>That handler uses an additional function called SetIsTextTrimmed. In a read-write attached property, that function is required to be present as that&#8217;s what WPF uses to write a new property value. In our case the property is read-only, so I still went ahead and created the function but marked it private:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:navy;">private</span> <span style="color:navy;">static</span> <span style="color:navy;">void</span> <span style="color:maroon;">SetIsTextTrimmed</span>( <span style="color:#a65300;">TextBlock</span> <span style="color:maroon;">target</span>, <span style="color:#2b91af;">Boolean</span> <span style="color:maroon;">value</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span>     <span style="color:maroon;">target</span>.<span style="color:maroon;">SetValue</span>( <span style="color:maroon;">IsTextTrimmedKey</span>, <span style="color:maroon;">value</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span> }</p>
</div>
<p><span style="font-size:xx-small;">(This uses the DependencyPropertyKey instance rather than the DependencyProperty object because SetValue has 2 overloads, one that takes a DependencyProperty (for read-write properties) and one that takes a DependencyProperty<strong>Key</strong> (for read-only properties). GetValue doesn&#8217;t care about writeability, so it only has a single version which expects a DependencyProperty instance.)</span></p>
<p>That actually covers the entirety of adding a (read-only) attached property to every TextBlock with the only usage requirements being (obviously) a reference to the TextBlockService assembly and (to use it from XAML) importing TextBlockService as a clr-namespace:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">tbs</span><span style="color:blue;">=&#8221;clr-namespace:TextBlockService;assembly=TextBlockService&#8221;</span></p>
</div>
<p>Once that&#8217;s imported, making use of the property is super easy (assuming you&#8217;ve figured out property triggers!)</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Some not-so-random text&#8221;</span><span style="color:red;"> TextTrimming</span><span style="color:blue;">=&#8221;WordEllipsis&#8221;</span><span style="color:red;"> TextWrapping</span><span style="color:blue;">=&#8221;NoWrap&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;TextBlock&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Trigger</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;tbs:TextBlockService.IsTextTrimmed&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  6</span> <span style="background:#ffffe6;">                    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;Background&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;Pink&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  7</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Trigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  8</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  9</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 10</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">TextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 11</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">TextBlock</span><span style="color:blue;">&gt;</span></p>
</div>
<p>And as always, the pudding:</p>
<p><a href="http://tranxcoder.files.wordpress.com/2008/10/image5.png"><img style="border-width:0;" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb5.png?w=156&#038;h=52" border="0" alt="image" width="156" height="52" /></a> <a href="http://tranxcoder.files.wordpress.com/2008/10/image6.png"><img style="border-width:0;" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb6.png?w=140&#038;h=52" border="0" alt="image" width="140" height="52" /></a></p>
<p>Don&#8217;t know about you, but I find that incredibly cool. We were able to develop and build an attached property in a class in a separate assembly and all that was needed to make use of it from a consuming application is to import the class&#8217; CLR namespace!</p>
<p>Now that we&#8217;ve built out our IsTextTrimmed attached property and shown how easy it is to use, let&#8217;s take it a step further and add an some additional custom TextBlock behavior into TextBlockService. I wanted to add an attached property that, when set to true for any given TextBlock, automatically enables a ToolTip that shows the hidden text whenever the text is being trimmed. I called that property TextBlockService.AutomaticToolTipEnabled and here&#8217;s how it works.</p>
<p>Like IsTextTrimmed, the AutomaticToolTipEnabled attached property does not have an associated dependency property that backs it. Unlike IsTextTrimmed, AutomaticToolTipEnabled is not a read-only property and, its implementation is much less involved since the property itself has no custom logic:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">readonly</span> <span style="color:#a65300;">DependencyProperty</span> <span style="color:maroon;">AutomaticToolTipEnabledProperty</span> = <span style="color:#a65300;">DependencyProperty</span>.<span style="color:maroon;">RegisterAttached</span>(</p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span>     <span style="background:#ffffe6;">&#8220;AutomaticToolTipEnabled&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span>     <span style="color:navy;">typeof</span>( <span style="color:navy;">bool</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span>     <span style="color:navy;">typeof</span>( <span style="color:#a65300;">TextBlockService</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span>     <span style="color:navy;">new</span> <span style="color:#a65300;">FrameworkPropertyMetadata</span>( <span style="color:navy;">true</span>, <span style="color:#2b91af;">FrameworkPropertyMetadataOptions</span>.<span style="color:maroon;">Inherits</span> ) );</p>
<p style="margin:0;"><span style="background:gray;color:white;">  6</span> </p>
<p style="margin:0;"><span style="background:gray;color:white;">  7</span> [<span style="color:#a65300;">AttachedPropertyBrowsableForType</span>( <span style="color:navy;">typeof</span>( <span style="color:#a65300;">DependencyObject</span> ) )]</p>
<p style="margin:0;"><span style="background:gray;color:white;">  8</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:#2b91af;">Boolean</span> <span style="color:maroon;">GetAutomaticToolTipEnabled</span>( <span style="color:#a65300;">DependencyObject</span> <span style="color:maroon;">element</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;">  9</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 10</span>     <span style="color:navy;">if</span> ( <span style="color:navy;">null</span> == <span style="color:maroon;">element</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 11</span>     {</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 12</span>         <span style="color:navy;">throw</span> <span style="color:navy;">new</span> <span style="color:#a65300;">ArgumentNullException</span>( <span style="background:#ffffe6;">&#8220;element&#8221;</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 13</span>     }</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 14</span>     <span style="color:navy;">return</span> (<span style="color:navy;">bool</span>) <span style="color:maroon;">element</span>.<span style="color:maroon;">GetValue</span>( <span style="color:maroon;">AutomaticToolTipEnabledProperty</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 15</span> }</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 16</span> </p>
<p style="margin:0;"><span style="background:gray;color:white;"> 17</span> <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">void</span> <span style="color:maroon;">SetAutomaticToolTipEnabled</span>( <span style="color:#a65300;">DependencyObject</span> <span style="color:maroon;">element</span>, <span style="color:navy;">bool</span> <span style="color:maroon;">value</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 18</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 19</span>     <span style="color:navy;">if</span> ( <span style="color:navy;">null</span> == <span style="color:maroon;">element</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 20</span>     {</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 21</span>         <span style="color:navy;">throw</span> <span style="color:navy;">new</span> <span style="color:#a65300;">ArgumentNullException</span>( <span style="background:#ffffe6;">&#8220;element&#8221;</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 22</span>     }</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 23</span>     <span style="color:maroon;">element</span>.<span style="color:maroon;">SetValue</span>( <span style="color:maroon;">AutomaticToolTipEnabledProperty</span>, <span style="color:maroon;">value</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;"> 24</span> }</p>
</div>
<p>Some additional differences to note are:</p>
<ol>
<li>The value defaults to <em>true</em>.</li>
<li>The value is automatically inherited by child elements.</li>
<li>The property can be attached to any DependencyObject.</li>
</ol>
<p>Points two and three are incredibly powerful when it comes to applying this property to multiple controls which makes it even more wonderful that all of that behavior is provided <em>for free</em> by the framework.</p>
<p>OK, so we&#8217;ve created a new attached property &#8211; but by itself that&#8217;s not going to provide any additional behavior. There are a lot of ways you could go about this, but the way I felt was most reusable under any number of scenarios was to create a ResourceDictionary (TextBlockServiceDictionary.xaml) with some simple property triggers.</p>
<div style="font-family:Consolas;font-size:10pt;color:black;background:#f8f8f8;">
<p style="margin:0;"><span style="color:white;background:gray;">  1</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">ResourceDictionary</span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  2</span>    <span style="color:red;">xmlns</span><span style="color:blue;">=<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a></span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  3</span>    <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">x</span><span style="color:blue;">=<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a></span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  4</span>    <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">tbs</span><span style="color:blue;">=&#8221;clr-namespace:TextBlockService&#8221;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  5</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;">  6</span> <span style="background:#ffffe6;">    </span><span style="color:green;">&lt;!&#8211;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  7</span> <span style="color:green;">    Rather than forcing *all* TextBlocks to adopt TextBlockService styles,</span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  8</span> <span style="color:green;">    using x:Key allows a more friendly opt-in model.</span></p>
<p style="margin:0;"><span style="color:white;background:gray;">  9</span> <span style="color:green;">    &#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 10</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;TextBlock&#8221;</span><span style="color:red;"> x</span><span style="color:blue;">:</span><span style="color:red;">Key</span><span style="color:blue;">=&#8221;TextBlockService&#8221;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 11</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 12</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">MultiTrigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 13</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">MultiTrigger.Conditions</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 14</span> <span style="background:#ffffe6;">                    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Condition</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;tbs:TextBlockService.AutomaticToolTipEnabled&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 15</span> <span style="background:#ffffe6;">                    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Condition</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;tbs:TextBlockService.IsTextTrimmed&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 16</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">MultiTrigger.Conditions</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 17</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;"> 18</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;ToolTip&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">={</span><span style="color:#a31515;">x</span><span style="color:blue;">:</span><span style="color:#a31515;">Static</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">.</span><span style="color:red;">Self</span><span style="color:blue;">},</span><span style="color:red;"> Path</span><span style="color:blue;">=Text}&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 19</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">MultiTrigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 20</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 21</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 22</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;"> 23</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">ResourceDictionary</span><span style="color:blue;">&gt;</span></p>
</div>
<p>First off, if you&#8217;ve never worked with resource dictionaries before, just think of it as a collection of resources (styles, templates, etc). If you import a dictionary, you import all of the resources it contains.</p>
<p>Two things are crucial here: First, I&#8217;m importing the TextBlockService CLR namespace, which means I automatically have access to the IsTextTrimmed attached property and the new AutomaticToolTipEnabled attached property.</p>
<p>Second, I&#8217;ve defined a style using TextBlock as the target type but also giving it an x:Key identifier. As a result, this style is considered an &#8220;explicit&#8221; style and will not be automatically applied to TextBlocks &#8211; something has to explicitly cause the style to be applied. I did this for several reasons, but a major one is that there are a lot of intricacies in WPF&#8217;s style system and many of them come into play when you attempt to use multiple implicit styles for the same type. As a result, it&#8217;s just easier for everyone if this style remains explicit. <em>(By the way, Ian Griffiths has a great </em><a title="Default Templates in WPF" href="http://www.interact-sw.co.uk/iangblog/2007/02/14/wpfdefaulttemplate" target="_blank"><em>blog entry</em></a><em> which explains default styles that I ran across while researching some of those intricacies.)</em></p>
<p>I defined a multi-condition trigger that says (in prose form): whenever AutomaticToolTipEnabled is true and IsTextTrimmed is true, set the value of the ToolTip property for this TextBlock to the value of the TextBlock&#8217;s Text property.</p>
<p>Making use of that style is also quite straightforward, it just requires merging in the resource dictionary. In addition to pulling in the styles, you also need to cause your TextBlocks to use the style. That&#8217;s easy to do and it&#8217;s also easy to cause those styles to apply to all TextBlocks in a control, window or even application (if it&#8217;s a WPF application.)</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">  1</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  2</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">ResourceDictionary</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  3</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">ResourceDictionary.MergedDictionaries</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  4</span> <span style="background:#ffffe6;">            </span><span style="color:green;">&lt;!&#8211; Merge in the TextBlockService style &#8211;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  5</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">ResourceDictionary</span><span style="color:red;"> Source</span><span style="color:blue;">=&#8221;/TextBlockService;component/TextBlockServiceDictionary.xaml&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  6</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">ResourceDictionary.MergedDictionaries</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  7</span> </p>
<p style="margin:0;"><span style="background:gray;color:white;">  8</span> <span style="background:#ffffe6;">        </span><span style="color:green;">&lt;!&#8211; Use BasedOn to apply TextBlockService behavior to every TextBlock in this Window &#8211;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">  9</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;TextBlock&#8221;</span><span style="color:red;"> BasedOn</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">StaticResource</span><span style="color:red;"> TextBlockService</span><span style="color:blue;">}&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 10</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 11</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextWrapping&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;NoWrap&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 12</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextTrimming&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;WordEllipsis&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 13</span> <span style="background:#ffffe6;">                </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;Text&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;Some not-so-random text&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 14</span> <span style="background:#ffffe6;">            </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 15</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 16</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">ResourceDictionary</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;"> 17</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
</div>
<p><span style="font-size:xx-small;">(Note: the ResourceDictionary.Source property uses Pack URI syntax which is <a title="Pack URI's in Windows Presentation Foundation" href="http://msdn.microsoft.com/en-us/library/aa970069.aspx" target="_blank">fairly well documented</a> on MSDN.)</span></p>
<p>In this case I&#8217;m not only applying the TextBlockService style to all my TextBlocks (by attaching it to my style via the BasedOn attribute), but I&#8217;m also adding some additional global properties. Remember, since the default value of AutomaticToolTipEnabled is true, the above fragment will enable the full host of functionality my TextBlockService has to offer for every TextBlock in that Window.</p>
<p>Finally, the AutomaticToolTipEnabled attached property can also be used in a more granular fashion:</p>
<div style="font-family:Consolas;font-size:10pt;color:black;background:#f8f8f8;">
<p style="margin:0;"><span style="color:white;background:gray;"> 25</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">StackPanel</span><span style="color:red;"> DockPanel.Dock</span><span style="color:blue;">=&#8221;Top&#8221;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 26</span> <span style="background:#ffffe6;">    </span><span style="color:green;">&lt;!&#8211; Adopts the default True value for AutomaticToolTipEnabled &#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 27</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 28</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;"> 29</span> <span style="background:#ffffe6;">    </span><span style="color:green;">&lt;!&#8211; Explicity sets AutomaticToolTipEnabled &#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 30</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:red;"> tbs</span><span style="color:blue;">:</span><span style="color:red;">TextBlockService.AutomaticToolTipEnabled</span><span style="color:blue;">=&#8221;False&#8221;</span><span style="color:red;"> Background</span><span style="color:blue;">=&#8221;LightGray&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 31</span> </p>
<p style="margin:0;"><span style="color:white;background:gray;"> 32</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Grid</span><span style="color:red;"> tbs</span><span style="color:blue;">:</span><span style="color:red;">TextBlockService.AutomaticToolTipEnabled</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 33</span> <span style="background:#ffffe6;">        </span><span style="color:green;">&lt;!&#8211; Inherits a value for AutomaticToolTipEnabled &#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 34</span> <span style="background:#ffffe6;">        </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 35</span> <span style="background:#ffffe6;">    </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Grid</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:white;background:gray;"> 36</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">StackPanel</span><span style="color:blue;">&gt;</span></p>
</div>
<p style="text-align:center;"><img style="border-width:0;" src="http://tranxcoder.files.wordpress.com/2009/02/customizinglookfulcontrolstake2hover.png?w=450" border="0" alt="image" /></p>
<p>Well, this post has droned on long enough. If you&#8217;re interested, please take a look at the Sample project I included in <a title="TextBlockService Sample Project" rel="nofollow" href="http://tranxcoder.files.wordpress.com/2009/02/textblockserviceexamplezip.doc">this zip file</a> (right click, Save As&#8230;, and change the extension to .zip &#8211; WordPress doesn&#8217;t permit uploading files with a .zip extension.)</p>
<p>And as I mentioned earlier, please feel free to leave questions, comments or suggestions. We&#8217;re all learning.</p>
<br />Posted in Code Tagged: WPF <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/92/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/92/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/92/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=92&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb5.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb6.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2009/02/customizinglookfulcontrolstake2hover.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Showing ToolTips on a trimmed TextBlock (WPF)</title>
		<link>http://tranxcoder.wordpress.com/2008/10/09/showing-tooltips-on-a-trimmed-textblock-wpf/</link>
		<comments>http://tranxcoder.wordpress.com/2008/10/09/showing-tooltips-on-a-trimmed-textblock-wpf/#comments</comments>
		<pubDate>Thu, 09 Oct 2008 23:36:22 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/10/09/showing-tooltips-on-a-trimmed-textblock-wpf/</guid>
		<description><![CDATA[[UPDATE: This solution has been superceded by a much better implementation in this later post.] I recently downloaded the WPF Toolkit for which Microsoft posted the first DataGrid CTP. That DataGrid is their attempt at responding to what is likely one of the most requested missing features in WPF. Many people have suggested that WPF [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=83&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><font color="#ff0000">[<strong>UPDATE</strong>: This solution has been superceded by a much better implementation in </font><a href="http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/"><font color="#0000ff">this later post</font></a><font color="#ff0000">.]</font></p>
<p>I recently downloaded the <a title="Windows Presentation Foundation (WPF) - Home" href="http://www.codeplex.com/wpf/Wiki/View.aspx?title=Toolkit%20Roadmap" target="_blank">WPF Toolkit</a> for which Microsoft posted the first DataGrid CTP. That DataGrid is their attempt at responding to what is likely one of the most requested missing features in WPF. Many people have suggested that <a title="Data grids - lack of imagination or abdication of design responsibility?" href="http://jcooney.net/archive/2008/06/09/55615.aspx" target="_blank">WPF doesn&#8217;t need a DataGrid</a> and may be better off not to provide one, but I <a title="Hristo Kosev's blog &gt; WPF Grids - to be or not to be" href="http://blogs.telerik.com/HristoKosev/Posts/08-06-11/WPF_Grids_to_be_or_not_to_be.aspx" target="_blank">and others</a> disagree &#8211; we do need a DataGrid, but it must be lookless! Anyway, I&#8217;m getting off topic.</p>
<p>While I really appreciate the work that went into building such a flexible and feature-packed control, I was quickly disheartened to learn that it has no mechanism built in to handle the scenario where column data (text) gets cut off due to size constraints. Actually there is one means, wrapping the text, but for the task I&#8217;m currently working on wrapping is really not an acceptable approach.</p>
</p>
<p><span id="more-83"></span>
<p>The obvious compromise is to display a ToolTip containing the full text when the mouse hovers over it. Easy enough to do by simply using a Style to add a ToolTip whose text is bound to the control&#8217;s content (fairly well documented <a title="Binding a ToolTip in XAML" href="http://blogs.msdn.com/tom_mathews/archive/2006/11/06/binding-a-tooltip-in-xaml.aspx" target="_blank">elsewhere</a>.)</p>
<p>There is one big problem that crops up with the simple hover invoked ToolTip, though. When the text is <strong>not</strong> being trimmed, a popup is still displayed which contains no additional information and obscures whatever data happens to be underneath it. At best it&#8217;s annoying for the user and worse could get in the way enough to slow them down.</p>
<p>My first thought was that surely there&#8217;s a property on TextBlock that I can hook up a property trigger to and only enable the ToolTip when that property is set. Something like, &#8220;IsTextTrimmed&#8221; or &#8220;HasParagraphEllipsis&#8221;, etc. Unfortunately, no such luck. Even worse, because TextBlock is a &#8220;lookful&#8221; control I can&#8217;t just pick apart its ControlTemplate to get after the information I need. <a title="Customizing &quot;lookful&quot; WPF controls &laquo; The Tranxition Developer Blog" href="http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/">My last blog post</a> described that problem in detail and the general approach taken to solve it.</p>
<p>In that post I presented a new custom control called EnhancedTextBlock which derives from TextBlock and uses reflection to provide an IsTextTrimmed read-only dependency property. Simply attaching a style trigger to that property offers the ability to easily adjust behavior based on whether or not the text is being trimmed. Here is a simple example of using that property to conditionally display a ToolTip:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 1</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 2</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;local:EnhancedTextBlock&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 3</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 4</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Trigger</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;IsTextTrimmed&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 5</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;ToolTip&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">={</span><span style="color:#a31515;">x</span><span style="color:blue;">:</span><span style="color:#a31515;">Static</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">.</span><span style="color:red;">Self</span><span style="color:blue;">},</span><span style="color:red;"> Path</span><span style="color:blue;">=Text}&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 6</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Trigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 7</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 8</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 9</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 10</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextWrapping&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;NoWrap&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 11</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextTrimming&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;WordEllipsis&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 12</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 13</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 14</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 15</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 16</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">StackPanel</span><span style="color:red;"> Margin</span><span style="color:blue;">=&#8221;40,0,40,0&#8243;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 17</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Short Text&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 18</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Slightly Longer Text&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 19</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">StackPanel</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Which produces something that works approximately like so:</p>
<p><a href="http://tranxcoder.files.wordpress.com/2008/10/image8.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb8.png?w=189&#038;h=98" width="189" height="98"></a> <a href="http://tranxcoder.files.wordpress.com/2008/10/image9.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb9.png?w=189&#038;h=98" width="189" height="98"></a> </p>
<p>Now that we&#8217;ve resolved conditional ToolTips in the general case, let&#8217;s get back to the WPF Toolkit&#8217;s DataGrid specifically.</p>
<p>First thing to realize is that we&#8217;re not going to be able to use the stock <em>DataGridBoundColumn</em> derived <em>DataGridTextColumn</em> because that control&#8217;s data template makes use of WPF&#8217;s TextBlock. Actually we could override the DataGridTextColumn&#8217;s ControlTemplate, but it turns out that&#8217;s not necessary! Vincent Sibal <a title="Stock and Template Columns" href="http://blogs.msdn.com/vinsibal/archive/2008/08/19/wpf-datagrid-stock-and-template-columns.aspx" target="_blank">has a post</a> describing a type of column control provided with the DataGrid called <em>DataGridTemplateColumn</em>. The sole purpose of that type is to allow us to provide our own custom data templates for both the view and edit case of any given column.</p>
<p>All that&#8217;s required is to first disable auto column generation (yes, unfortunately that&#8217;s one of the drawbacks of this approach) and second, add a column with a CellTemplate that includes our EnhancedTextBlock control:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 35</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid</span><span style="color:red;"> AutoGenerateColumns</span><span style="color:blue;">=&#8221;False&#8221;</span><span style="color:red;"> ItemsSource</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:blue;">}&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 36</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid.Columns</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 37</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn</span><span style="color:red;"> Header</span><span style="color:blue;">=&#8221;Various Text&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 38</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn.CellTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 39</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">DataTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 40</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:blue;">}&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 41</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">DataTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 42</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn.CellTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 43</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 44</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid.Columns</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 45</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Then spice it up with our style setters and triggers from above and we end up with this lovely bit of XAML:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 1</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">Window</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 2</span>&nbsp;<span style="color:red;">&nbsp;&nbsp;&nbsp; x</span><span style="color:blue;">:</span><span style="color:red;">Class</span><span style="color:blue;">=&#8221;WpfApplication1.Window1&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 3</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">local</span><span style="color:blue;">=&#8221;clr-namespace:WpfApplication1&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 4</span>&nbsp;<span style="color:red;">&nbsp;&nbsp;&nbsp; xmlns</span><span style="color:blue;">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 5</span>&nbsp;<span style="color:red;">&nbsp;&nbsp;&nbsp; xmlns</span><span style="color:blue;">:</span><span style="color:red;">x</span><span style="color:blue;">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 6</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">dg</span><span style="color:blue;">=&#8221;http://schemas.microsoft.com/wpf/2008/toolkit&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 7</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">sys</span><span style="color:blue;">=&#8221;clr-namespace:System;assembly=mscorlib&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 8</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">collections</span><span style="color:blue;">=&#8221;clr-namespace:System.Collections;assembly=mscorlib&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 9</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">Width</span><span style="color:blue;">=&#8221;600&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 10</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">Height</span><span style="color:blue;">=&#8221;125&#8243;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 11</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 12</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Window.DataContext</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 13</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">collections</span><span style="color:blue;">:</span><span style="color:#a31515;">ArrayList</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 14</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span><span style="background:#ffffe6;">Short Text</span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 15</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span><span style="background:#ffffe6;">Slightly Longer Text</span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 16</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span><span style="background:#ffffe6;">Text that is so long it makes you wonder if a non-wrapping datagrid cell is really the best way to present it</span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">sys</span><span style="color:blue;">:</span><span style="color:#a31515;">String</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 17</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">collections</span><span style="color:blue;">:</span><span style="color:#a31515;">ArrayList</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 18</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window.DataContext</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 19</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 20</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 21</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;local:EnhancedTextBlock&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 22</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 23</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Trigger</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;IsTextTrimmed&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 24</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;ToolTip&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">={</span><span style="color:#a31515;">x</span><span style="color:blue;">:</span><span style="color:#a31515;">Static</span><span style="color:red;"> RelativeSource</span><span style="color:blue;">.</span><span style="color:red;">Self</span><span style="color:blue;">},</span><span style="color:red;"> Path</span><span style="color:blue;">=Text}&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 25</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Trigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 26</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 27</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 28</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 29</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextWrapping&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;NoWrap&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 30</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;TextTrimming&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;WordEllipsis&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 31</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Setters</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 32</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 33</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 34</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 35</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid</span><span style="color:red;"> AutoGenerateColumns</span><span style="color:blue;">=&#8221;False&#8221;</span><span style="color:red;"> ItemsSource</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:blue;">}&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 36</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid.Columns</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 37</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn</span><span style="color:red;"> Header</span><span style="color:blue;">=&#8221;Various Text&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 38</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn.CellTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 39</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">DataTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 40</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;{</span><span style="color:#a31515;">Binding</span><span style="color:blue;">}&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 41</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">DataTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 42</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn.CellTemplate</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 43</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGridTemplateColumn</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 44</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid.Columns</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 45</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">dg</span><span style="color:blue;">:</span><span style="color:#a31515;">DataGrid</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 46</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window</span><span style="color:blue;">&gt;</span></p>
</div>
<p>And as always, I like to demonstrate my flare with visual aids:</p>
<p><a href="http://tranxcoder.files.wordpress.com/2008/10/image10.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb10.png?w=535&#038;h=157" width="535" height="157"></a> </p>
<p>Ultimately, it&#8217;s not a very <em>tidy</em> solution because the original trick to add an <em>IsTextTrimmed</em> property required creating a custom control rather than just using the built-in TextBlock and it makes use of reflection which means the EnhancedTextBlock can&#8217;t be used in partial-trust applications. Those issues aside, I have at least shown that if you&#8217;re willing to accept a few compromises and do some heavy lifting, deep customization of &#8220;lookful&#8221; WPF controls can be achieved. I&#8217;ve also shown that making use of custom controls in the WPF Toolkit DataGrid is really quite straightforward.</p>
<br />Posted in Code Tagged: WPF <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/83/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=83&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/10/09/showing-tooltips-on-a-trimmed-textblock-wpf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb8.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb9.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb10.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Customizing &#8220;lookful&#8221; WPF controls</title>
		<link>http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/</link>
		<comments>http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/#comments</comments>
		<pubDate>Thu, 09 Oct 2008 07:27:57 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/</guid>
		<description><![CDATA[[UPDATE: This solution has been superceded by a much better implementation in this later post.] If you&#8217;ve spent any time reading material about WPF, it&#8217;s inevitable that the term &#8220;lookless&#8221; has come up at least once. Ironically, that&#8217;s not actually a word, at least not according to Webster. However, the term has been drilled into [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=75&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><font color="#ff0000">[<strong>UPDATE</strong>: This solution has been superceded by a much better implementation in </font><a href="http://tranxcoder.wordpress.com/2008/10/12/customizing-lookful-wpf-controls-take-2/"><font color="#0000ff">this later post</font></a><font color="#ff0000">.]</font></p>
<p>If you&#8217;ve spent any time reading material about WPF, it&#8217;s inevitable that the term &#8220;lookless&#8221; has come up at least once. Ironically, that&#8217;s not actually a word, at least <a title="Merriam-Webster Online" href="http://www.merriam-webster.com/dictionary/lookless" target="_blank">not according to Webster</a>. However, the term has been drilled into the minds of WPF developers the world over and will likely be added to the <a title="The words &quot;Friendster,&quot; &quot;Klum,&quot; &quot;Nazr,&quot; ..." href="http://support.microsoft.com/?kbid=955020" target="_blank">Windows dictionary</a> at some point. Microsoft even used the word several times in this <a title="0050091584" href="http://appft1.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;Sect2=HITOFF&amp;p=1&amp;u=%2Fnetahtml%2FPTO%2Fsearch-bool.html&amp;r=1&amp;f=G&amp;l=50&amp;co1=AND&amp;d=PG01&amp;s1=20050091584&amp;OS=20050091584&amp;RS=20050091584" target="_blank">patent application</a> which describes in precise detail what it means. In case the practical meaning isn&#8217;t clear, in essence &#8220;lookless&#8221; equates to &#8220;has a flexible UI&#8221;. In other words, lookless controls are focused on functionality, not appearance or even visual behavior. Of course most controls do have a default appearance, but lookless controls are, by nature, almost completely customizable (limited mostly by imagination and time.)</p>
<p>Matt Duffin of the UK even <a title="The Joys of Lookless" href="http://wpfopoly.blogspot.com/2007/08/joys-of-lookless.html" target="_blank">suggested</a> we all grab a pen and write &#8220;All controls in WPF should be lookless&#8221; over and over until it becomes ingrained. Not sure I would go that far, but clearly the overwhelming guidance for WPF designers is that most controls <em>should</em> have a stylable and/or templatable appearance which is independent of functionality. Being aware of that guidance just makes it even more frustrating when you run into a control built into the framework which violates that tenet.</p>
<p>The particular control I&#8217;m referring to in this case is the <a title="TextBlock Class (System.Windows.Controls)" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.textblock.aspx" target="_blank">TextBlock</a>. Recently I had a desire to enable <a title="ToolTip Overview" href="http://msdn.microsoft.com/en-us/library/ms754034.aspx" target="_blank">ToolTips</a> on a TextBlock when (and only when) its text is being trimmed. I&#8217;ve written <a href="http://tranxcoder.wordpress.com/2008/10/09/showing-tooltips-on-a-trimmed-textblock-wpf/">a separate post</a> which goes into the solution to that specific problem in more depth, but getting there required a lot of foundational work which can be applied to address any number of issues.</p>
</p>
<p><span id="more-75"></span>
</p>
<p>Unlike most of the built-in WPF controls which derive from the <a title="Control Class (System.Windows.Controls)" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.control.aspx" target="_blank">Control</a> class, TextBlock derives directly from the <a title="FrameworkElement Class (System.Windows)" href="http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.aspx" target="_blank">FrameworkElement</a> class. <a title="Control Authoring Overview" href="http://msdn.microsoft.com/en-us/library/ms745025.aspx" target="_blank">MSDN says</a> there are two standard methods for building FrameworkElement-based components: direct rendering and custom element composition. TextBlock performs direct rendering because it overrides the OnRender method and provides DrawingContext operations that explicitly define the component visuals. It also performs custom element composition because it uses other visual components like <a title="Flow Document Overview" href="http://msdn.microsoft.com/en-us/library/aa970909.aspx" target="_blank">Flow Documents</a> to provide its content. What&#8217;s most important to this discussion is simply that TextBlock does not derive from <a title="Control Class (System.Windows.Controls)" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.control.aspx" target="_blank">Control</a> thus its visual appearance can not be changed by simply overriding its <a title="ControlTemplate Class (System.Windows.Controls)" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.controltemplate.aspx" target="_blank">ControlTemplate</a> (which is extremely <a title="Create or edit a control template" href="http://msdn.microsoft.com/en-us/library/cc294908.aspx" target="_blank">easy to do</a> via Expression Blend.) What this means for would-be direct rendering control customizers is that we&#8217;ve got a lot more work to do.</p>
<p>For instance, let&#8217;s say I want to display a different background in the TextBlock based on whether or not the text inside it is being trimmed. Telling the TextBlock to trim is simple enough:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 1</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:red;"> TextTrimming</span><span style="color:blue;">=&#8221;WordEllipsis&#8221;</span><span style="color:red;"> TextWrapping</span><span style="color:blue;">=&#8221;NoWrap&#8221;</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Some not-so-random text&#8221; /&gt;</span></p>
</div>
<p>Now whenever the TextBlock isn&#8217;t given enough space to display the full text, it will automatically clip the text and append an ellipsis (…). In order to provide a different background based on the state of a control, typically you can make use of a style trigger &#8211; which is exactly what I&#8217;ll attempt in this case:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 1</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock</span><span style="color:red;"> TextTrimming</span><span style="color:blue;">=&#8221;WordEllipsis&#8221;</span><span style="color:red;"> TextWrapping</span><span style="color:blue;">=&#8221;NoWrap&#8221;</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Some not-so-random text&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 2</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">TextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 3</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;TextBlock&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 4</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 5</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Trigger</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;<font color="#ff0000" size="3" face="Tahoma"><strong>?</strong></font>&#8220;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 6</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;Background&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;HotPink&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 7</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Trigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 8</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 9</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 10</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">TextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 11</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">TextBlock</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Ah, right. It appears I&#8217;m missing an important bit of information. That big red question-mark above is referring to a dependency property on TextBlock to which we need to bind in order to determine whether the text is being trimmed. However, there is no such property documented for TextBlock. In actual fact, no such property exists at all, but I&#8217;ll get to that in a moment.</p>
<p>First I want to point out that the easiest way to resolve these situations for normal controls is to access their control template and start looking for relevant triggers and properties. In many cases you&#8217;ll find that the control provides exactly the information you need and it&#8217;s just a matter of applying a property trigger or a slightly altered template to get the desired behavior (or appearance.) For example, the control template for the <a title="CheckBox Class (System.Windows.Controls)" href="http://msdn.microsoft.com/en-us/library/system.windows.controls.checkbox.aspx" target="_blank">CheckBox</a> class is <a title="CheckBox ControlTemplate Example" href="http://msdn.microsoft.com/en-us/library/ms752319.aspx" target="_blank">laid out on MSDN</a> and with just a quick glance I see that the checkmark graphic is created by a border brush with a predefined path. Again, the ways in which you can customize that control&#8217;s appearance and behavior are virtually limitless.</p>
<p>Not so for the TextBlock. Because there&#8217;s no control template we&#8217;ll have to resort to poking around with <a title=".NET Reflector, class browser, analyzer and decompiler for .NET" href="http://www.red-gate.com/products/reflector/index.htm" target="_blank">Reflector</a> (which, in case you hadn&#8217;t heard, is <a title="The Future of .NET Reflector" href="http://blog.lutzroeder.com/2008/08/future-of-net-reflector.html" target="_blank">now owned by Red Gate Software</a>, not Lutz Roeder.) I couldn&#8217;t possibly recall everything I did to arrive with this solution, apart from attaching a time-sliced video of my computer in action as I traversed up and down class hierarchies and ran innumerable expressions in my debugger&#8217;s Immediate Window. Suffice to say it was a lot of digging and comprehending and ultimately, a lot of guessing that led me to the conclusion that the simplest and most direct way to determine if a TextBlock is currently trimming the text is to compare the Width property of <a title="UIElement.RenderSize Property (System.Windows)" href="http://msdn.microsoft.com/en-us/library/system.windows.uielement.rendersize.aspx" target="_blank">RenderSize</a> with the Width property of a private instance field named &#8220;_firstLine&#8221; inside the OnRenderSizeChanged method.</p>
<p>For that to be possible, we&#8217;ll have to create a new control which derives from TextBlock and override its OnRenderSizeChanged. Additionally, reflection will be necessary in order to access private members of the base class. Sadly that does mean we&#8217;re going to deliberately degrade the control&#8217;s performance and, as such, this technique should only be used as a last resort. That&#8217;s not the only reason, though. Microsoft does not guarantee that the internal implementation details of any of its libraries won&#8217;t change drastically between versions. Which means even though this code works on .NET Framework 3.5 SP1, it may not work at all for the next service pack or major release. The code I&#8217;m presenting is not robust and should be augmented with mechanisms to deal with that scenario.</p>
<p>Speaking of code, here it is. In order to publish information about the control&#8217;s trimming status I added a read-only dependency property named IsTextTrimmed. I&#8217;m also caching the reflected type information so the only repeat performance hit is actually retrieving the values:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 1</span>&nbsp;<span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 2</span>&nbsp;<span style="color:gray;">///</span><span style="color:green;"> Adds the read-only dependency property </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">IsTextTrimmed</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;"> to the built-in</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 3</span>&nbsp;<span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;see cref=&#8221;TextBlock&#8221;/&gt;</span><span style="color:green;"> </span><span style="color:gray;">&lt;see cref=&#8221;FrameworkElement&#8221;/&gt;</span><span style="color:green;">.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 4</span>&nbsp;<span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 5</span>&nbsp;<span style="color:navy;">public</span> <span style="color:navy;">class</span> <span style="color:#a65300;">EnhancedTextBlock</span> : <span style="color:#a65300;">TextBlock</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 6</span> {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 7</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #region</span> Members</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 8</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 9</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 10</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Accessor for the </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">_firstLine</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;"> private instance field of the </span><span style="color:gray;">&lt;see cref=&#8221;TextBlock&#8221;/&gt;</span><span style="color:green;"> class.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 11</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 12</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">private</span> <span style="color:navy;">static</span> <span style="color:#a65300;">FieldInfo</span> <span style="color:maroon;">_firstLineField</span> = <span style="color:navy;">typeof</span>( <span style="color:#a65300;">TextBlock</span> ).<span style="color:maroon;">GetField</span>( <span style="background:#ffffe6;">&#8220;_firstLine&#8221;</span>, <span style="color:#2b91af;">BindingFlags</span>.<span style="color:maroon;">NonPublic</span> | <span style="color:#2b91af;">BindingFlags</span>.<span style="color:maroon;">Instance</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 13</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 14</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 15</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Accessor for the </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">Width</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;"> internal instance property of the </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">MS.Internal.Text.LineMetrics</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;"> struct.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 16</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 17</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">private</span> <span style="color:navy;">static</span> <span style="color:#a65300;">PropertyInfo</span> <span style="color:maroon;">_lineMetricsWidthProperty</span> = <span style="color:maroon;">_firstLineField</span>.<span style="color:maroon;">FieldType</span>.<span style="color:maroon;">GetProperty</span>( <span style="background:#ffffe6;">&#8220;Width&#8221;</span>, <span style="color:#2b91af;">BindingFlags</span>.<span style="color:maroon;">NonPublic</span> | <span style="color:#2b91af;">BindingFlags</span>.<span style="color:maroon;">Instance</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 18</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 19</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #endregion</span> (Members)</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 20</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 21</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #region</span> Dependency Properties</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 22</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 23</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 24</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Key returned upon registering the read-only dependency property </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">IsTextTrimmed</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;">.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 25</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 26</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">readonly</span> <span style="color:#a65300;">DependencyPropertyKey</span> <span style="color:maroon;">IsTextTrimmedKey</span> = <span style="color:#a65300;">DependencyProperty</span>.<span style="color:maroon;">RegisterReadOnly</span>(</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background:#ffffe6;">&#8220;IsTextTrimmed&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">typeof</span>( <span style="color:navy;">bool</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">typeof</span>( <span style="color:#a65300;">EnhancedTextBlock</span> ),</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">PropertyMetadata</span>( <span style="color:navy;">false</span> ) );&nbsp;&nbsp;&nbsp; <span style="color:green;">// defaults to false</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 31</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 32</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 33</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Identifier associated with the read-only dependency property </span><span style="color:gray;">&lt;c&gt;</span><span style="color:green;">IsTextTrimmed</span><span style="color:gray;">&lt;/c&gt;</span><span style="color:green;">.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 34</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 35</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">static</span> <span style="color:navy;">readonly</span> <span style="color:#a65300;">DependencyProperty</span> <span style="color:maroon;">IsTextTrimmedProperty</span> = <span style="color:maroon;">IsTextTrimmedKey</span>.<span style="color:maroon;">DependencyProperty</span>;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 36</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 37</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #endregion</span> (Dependency Properties)</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 38</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 39</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #region</span> Properties</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 40</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 41</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 42</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Gets the current effective value of the IsTextTrimmed dependency property.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 43</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 44</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">bool</span> <span style="color:maroon;">IsTextTrimmed</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 45</span>&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">get</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">return</span> (<span style="color:navy;">bool</span>) <span style="color:maroon;">GetValue</span>( <span style="color:maroon;">IsTextTrimmedProperty</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 50</span>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 51</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 52</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #endregion</span> (Properties)</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 53</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 54</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #region</span> Methods</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 55</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 56</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 57</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Raises the SizeChanged event, using the specified information as part of the eventual event data.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 58</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 59</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;param name=&#8221;sizeInfo&#8221;&gt;</span><span style="color:green;">Details of the old and new size involved in the change</span><span style="color:gray;">&lt;/param&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 60</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">protected</span> <span style="color:navy;">override</span> <span style="color:navy;">void</span> <span style="color:maroon;">OnRenderSizeChanged</span>( <span style="color:#a65300;">SizeChangedInfo</span> <span style="color:maroon;">sizeInfo</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 61</span>&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">base</span>.<span style="color:maroon;">OnRenderSizeChanged</span>( <span style="color:maroon;">sizeInfo</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 63</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 64</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:maroon;">SetIsTextTrimmed</span>();</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 65</span>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 66</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 67</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 68</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Sets the local value of read-only dependency property </span><span style="color:gray;">&lt;see cref=&#8221;IsTextTrimmed&#8221;/&gt;</span><span style="color:green;">.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 69</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/summary&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 70</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;remarks&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 71</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Uses reflection to access private and internal members of the base TextBlock class.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 72</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> Therefore, this method may introduce a significant performance drain.</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 73</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:gray;">///</span><span style="color:green;"> </span><span style="color:gray;">&lt;/remarks&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 74</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">private</span> <span style="color:navy;">void</span> <span style="color:maroon;">SetIsTextTrimmed</span>()</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 75</span>&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 76</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">if</span> ( <span style="color:#2b91af;">TextTrimming</span>.<span style="color:maroon;">None</span> == <span style="color:maroon;">TextTrimming</span> )</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 77</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 78</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:maroon;">SetValue</span>( <span style="color:maroon;">IsTextTrimmedKey</span>, <span style="color:navy;">false</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 79</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 80</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">else</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 81</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 82</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2b91af;">Double</span> <span style="color:maroon;">firstLineWidth</span> = (<span style="color:#2b91af;">Double</span>) <span style="color:maroon;">_lineMetricsWidthProperty</span>.<span style="color:maroon;">GetValue</span>( <span style="color:maroon;">_firstLineField</span>.<span style="color:maroon;">GetValue</span>( <span style="color:navy;">this</span> ), <span style="color:navy;">null</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 83</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2b91af;">Double</span> <span style="color:maroon;">renderWidth</span> = <span style="color:maroon;">RenderSize</span>.<span style="color:maroon;">Width</span>;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 84</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 85</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:maroon;">SetValue</span>( <span style="color:maroon;">IsTextTrimmedKey</span>, <span style="color:maroon;">firstLineWidth</span> &gt; <span style="color:maroon;">renderWidth</span> );</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 86</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 87</span>&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 88</span>&nbsp;</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 89</span>&nbsp;<span style="color:blue;">&nbsp;&nbsp;&nbsp; #endregion</span> (Methods)</p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 90</span> }</p>
</div>
<p>All that&#8217;s left is to modify our original markup to make use of the new and improved EnhancedTextBlock and replace the question-mark with our custom IsTextTrimmed property:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 1</span>&nbsp;<span style="color:blue;">&lt;</span><span style="color:#a31515;">Window</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 2</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 3</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">x</span><span style="color:blue;">=&#8221;http://schemas.microsoft.com/winfx/2006/xaml&#8221;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 4</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">x</span><span style="color:blue;">:</span><span style="color:red;">Class</span><span style="color:blue;">=&#8221;WpfApplication1.Window1&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 5</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">xmlns</span><span style="color:blue;">:</span><span style="color:red;">local</span><span style="color:blue;">=&#8221;clr-namespace:WpfApplication1&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 6</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">Height</span><span style="color:blue;">=&#8221;54&#8243;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 7</span>&nbsp;&nbsp;&nbsp; <span style="color:red;">Width</span><span style="color:blue;">=&#8221;120&#8243;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 8</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Grid</span><span style="color:red;"> HorizontalAlignment</span><span style="color:blue;">=&#8221;Center&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp;&nbsp; 9</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:red;"> TextTrimming</span><span style="color:blue;">=&#8221;WordEllipsis&#8221;</span><span style="color:red;"> TextWrapping</span><span style="color:blue;">=&#8221;NoWrap&#8221;</span><span style="color:red;"> Text</span><span style="color:blue;">=&#8221;Some not-so-random text&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 10</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 11</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style</span><span style="color:red;"> TargetType</span><span style="color:blue;">=&#8221;local:EnhancedTextBlock&#8221;&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 12</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><em><span style="background:gray;color:white;">&nbsp;&nbsp; 13</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Trigger</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;<strong>IsTextTrimmed</strong>&#8220;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;True&#8221;&gt;</span></em></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 14</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;</span><span style="color:#a31515;">Setter</span><span style="color:red;"> Property</span><span style="color:blue;">=&#8221;Background&#8221;</span><span style="color:red;"> Value</span><span style="color:blue;">=&#8221;HotPink&#8221; /&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 15</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Trigger</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 16</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style.Triggers</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 17</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Style</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 18</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock.Resources</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 19</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">local</span><span style="color:blue;">:</span><span style="color:#a31515;">EnhancedTextBlock</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 20</span>&nbsp;<span style="background:#ffffe6;">&nbsp;&nbsp;&nbsp; </span><span style="color:blue;">&lt;/</span><span style="color:#a31515;">Grid</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="background:gray;color:white;">&nbsp;&nbsp; 21</span>&nbsp;<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Window</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Finally, last but not least &#8211; evidence that the background color does change if (and only if) the text is being trimmed:</p>
<p><a href="http://tranxcoder.files.wordpress.com/2008/10/image.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb.png?w=175&#038;h=57" width="175" height="57"></a> <a href="http://tranxcoder.files.wordpress.com/2008/10/image1.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/10/image-thumb1.png?w=127&#038;h=58" width="127" height="58"></a></p>
<p>What&#8217;s left to say except, &#8220;That&#8217;s Hot!&#8221;</p>
<br />Posted in Code Tagged: WPF <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/75/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/75/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/75/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=75&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/10/09/customizing-lookful-wpf-controls/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/10/image-thumb1.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
		<item>
		<title>Disposable C# Snippets</title>
		<link>http://tranxcoder.wordpress.com/2008/07/17/disposable-c-snippets/</link>
		<comments>http://tranxcoder.wordpress.com/2008/07/17/disposable-c-snippets/#comments</comments>
		<pubDate>Thu, 17 Jul 2008 20:16:31 +0000</pubDate>
		<dc:creator>cgassib</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/07/17/disposable-c-snippets/</guid>
		<description><![CDATA[Visual Studio code snippets were brought up a couple times today.&#160; Which reminded me of the only two snippets I&#8217;ve ever written and used.&#160; I think they&#8217;re useful to save me some typing.&#160; In C# whenever you have some class that is holding onto unmanaged resources, or even a lot of managed resources, you really [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=61&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Visual Studio code snippets were brought up a couple times today.&nbsp; Which reminded me of the only two snippets I&#8217;ve ever written and used.&nbsp; I think they&#8217;re useful to save me some typing.&nbsp; In C# whenever you have some class that is holding onto unmanaged resources, or even a lot of managed resources, you really need to make it IDisposable.&nbsp; The problem is it&#8217;s a fair amount of repetitive typing to get there.&nbsp; </p>
<p><span id="more-61"></span>
</p>
<p>I have two versions: one for a base class and one for a derived class.&nbsp; You use the Base Dispose Pattern snippet if your class is the first class in your hierarchy that implements IDisposable.&nbsp; You use the Derived Dispose Pattern snippet if your class is derived from another class that implements IDisposable.&nbsp; Just put your caret on a line within class scope, but outside method scope.&nbsp; Hit the old &#8220;Ctrl K X&#8221;, select &#8220;My Code Snippets&#8221; from the context menu, then find the correct Dispose Pattern.&nbsp; Don&#8217;t forget to add IDisposable to your class definition if it&#8217;s a base disposable class.</p>
<p>After the snippet is pasted you&#8217;ll have a couple sections to fill in.&nbsp; The fill in sections are marked with comments.&nbsp; The managed section is where you clean up your managed member data.&nbsp; You would do this by calling Dispose() on IDisposable types and breaking references by setting them to null.&nbsp; This makes it easier for the garbage collector to know what to clean up.&nbsp; For example:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:green;">// if x is a disposable type:</span></p>
<p style="margin:0;"><span style="color:blue;">if</span> (x != <span style="color:blue;">null</span>)</p>
<p style="margin:0;">{</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; x.Dispose();</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; x = <span style="color:blue;">null</span>;</p>
<p style="margin:0;">}</p>
<p style="margin:0;">&nbsp;</p>
<p style="margin:0;"><span style="color:green;">// if x is not a disposable reference type:</span></p>
<p style="margin:0;">x = <span style="color:blue;">null</span>;</p>
</div>
<p>The unmanaged section is where you would clean up any native resources used by your class.&nbsp; For example: you would close any open win32 handles there.</p>
<p>The disposed member variable can be used in debugging to find out if your object is being referenced after it&#8217;s been disposed.&nbsp; This is a bad thing, but you can quickly check for it by using code like the following:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:blue;">public</span> <span style="color:blue;">void</span> MyMethod()</p>
<p style="margin:0;">{</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; <span style="color:blue;">if</span> (disposed)</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; {</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:blue;">throw</span> <span style="color:blue;">new</span> ObjectDisposedException(<span style="color:#a31515;">&#8220;MyClass.MyMethod() called on disposed object!&#8221;</span>);</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; }</p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp; <span style="color:green;">// TODO: write method code.</span></p>
<p style="margin:0;">}</p>
</div>
<p>Copy these two files into your DocumentsVisual Studio 2008Code SnippetsVisual C#My Code Snippets folder:</p>
<p>Base Dispose Pattern.snippet:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:blue;"> </span><span style="color:red;">version</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">encoding</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">utf-8</span>&#8220;<span style="color:blue;">?&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&lt;</span><span style="color:#a31515;">CodeSnippets</span><span style="color:blue;"> </span><span style="color:red;">xmlns</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp; &lt;</span><span style="color:#a31515;">CodeSnippet</span><span style="color:blue;"> </span><span style="color:red;">Format</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0.0</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Header</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Title</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base Dispose Pattern</p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Title</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Header</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Snippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Declarations</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Literal</span><span style="color:blue;"> </span><span style="color:red;">Editable</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">false</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span>classname<span style="color:blue;">&lt;/</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">ToolTip</span><span style="color:blue;">&gt;</span>The name of this class.<span style="color:blue;">&lt;/</span><span style="color:#a31515;">ToolTip</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Default</span><span style="color:blue;">&gt;</span>BaseResource<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Default</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Function</span><span style="color:blue;">&gt;</span>ClassName()<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Function</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Literal</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Declarations</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Code</span><span style="color:blue;"> </span><span style="color:red;">Language</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">CSharp</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;![CDATA[</span><span style="color:gray;">private bool disposed = false;</span></p>
<p style="margin:0;">&nbsp;</p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void Dispose()</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispose(true);</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GC.SuppressFinalize(this);</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;">&nbsp;</p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected virtual void Dispose(bool disposing)</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!disposed)</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (disposing) // Managed:</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Unmanaged:</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disposed = true;</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;">&nbsp;</p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~$classname$()</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispose(false);</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><span style="color:blue;">]]&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Code</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Snippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp; &lt;/</span><span style="color:#a31515;">CodeSnippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&lt;/</span><span style="color:#a31515;">CodeSnippets</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Derived Dispose Pattern.snippet:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:blue;"> </span><span style="color:red;">version</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">encoding</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">utf-8</span>&#8220;<span style="color:blue;">?&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&lt;</span><span style="color:#a31515;">CodeSnippets</span><span style="color:blue;"> </span><span style="color:red;">xmlns</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp; &lt;</span><span style="color:#a31515;">CodeSnippet</span><span style="color:blue;"> </span><span style="color:red;">Format</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0.0</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Header</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Title</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Derived Dispose Pattern</p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Title</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Header</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Snippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</span><span style="color:#a31515;">Code</span><span style="color:blue;"> </span><span style="color:red;">Language</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">CSharp</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;![CDATA[</span><span style="color:gray;">private bool disposed = false;</span></p>
<p style="margin:0;">&nbsp;</p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected override void Dispose(bool disposing)</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!disposed)</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (disposing) // Managed:</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Unmanaged:</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disposed = true;</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; finally</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; base.Dispose(disposing);</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p style="margin:0;"><span style="color:gray;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><span style="color:blue;">]]&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Code</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp;&nbsp;&nbsp; &lt;/</span><span style="color:#a31515;">Snippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&nbsp; &lt;/</span><span style="color:#a31515;">CodeSnippet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:blue;">&lt;/</span><span style="color:#a31515;">CodeSnippets</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Enjoy!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/tranxcoder.wordpress.com/61/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/tranxcoder.wordpress.com/61/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/61/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=61&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/07/17/disposable-c-snippets/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">cgassib</media:title>
		</media:content>
	</item>
		<item>
		<title>A Generic Factory in C#</title>
		<link>http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c/</link>
		<comments>http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c/#comments</comments>
		<pubDate>Fri, 11 Jul 2008 22:32:26 +0000</pubDate>
		<dc:creator>cgassib</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[C#]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c/</guid>
		<description><![CDATA[There is this really popular OOP design pattern that we at Tranxition, and other developers elsewhere, use frequently.  Years ago, after reading about the factory pattern in the GOF book I immediately thought of some possible uses for it in my work.  I was really excited to code it up&#8230; the first time.  After having [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=57&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There is this really popular OOP design pattern that we at Tranxition, and other developers elsewhere, use frequently.  Years ago, after reading about the factory pattern in the GOF book I immediately thought of some possible uses for it in my work.  I was really excited to code it up&#8230; the first time.  After having writing the code for one factory though, it was clear to me it should just be a library and there were some things overlooked by most example implementations.</p>
<p><span id="more-57"></span>Here&#8217;s a classic example from a simple drawing program:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">ShapeFactory</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Shape</span> CreateObject(<span style="color:#2b91af;">ShapeName</span> shapeName)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">switch</span> (shapeName)</p>
<p style="margin:0;">        {</p>
<p style="margin:0;">            <span style="color:#0000ff;">case</span> <span style="color:#2b91af;">ShapeName</span>.Circle:</p>
<p style="margin:0;">                <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Circle</span>();</p>
<p style="margin:0;">            <span style="color:#0000ff;">case</span> <span style="color:#2b91af;">ShapeName</span>.Square:</p>
<p style="margin:0;">                <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Square</span>();</p>
<p style="margin:0;">            <span style="color:#0000ff;">default</span>:</p>
<p style="margin:0;">                <span style="color:#0000ff;">throw</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Exception</span>(<span style="color:#a31515;">&#8220;unknown shape type&#8221;</span>);</p>
<p style="margin:0;">        }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>The solution this ShapeFactory provides is pretty cool actually.  Now, if you need to add a new shape to the screen you just call one function.  Most of your code doesn&#8217;t have to know the details of the shape the user wants to create.  You just call the CreateObject() method passing the shape&#8217;s name and you get back a reference to generic shape object that can be stored in any shape container.  The shape container gets passed along and presumably gets a virtual Shape.Draw() method called on all of its contents in a foreach loop.</p>
<p>That&#8217;s really awesome until you want to add Triangles to your drawing program.  You probably start by adding a new Triangle.cs class file to your project.  Nice and OOP-y so far.  But then you have to crack open the ShapeName enumeration to add a new identifier for your Triangle class.  Next you have to crack open the switch statement of your ShapeFactory.CreateObject() method to add a case for your new Triangle class.  That&#8217;s two violations of the <a href="http://en.wikipedia.org/wiki/Open_Closed_Principle">open/closed principle</a>.  That&#8217;s not so awesome.  I like making as few changes as possible to existing code when adding features.<br />
You&#8217;ll notice that the switch statement is really switching on a type.  That sounds familiar, like I&#8217;ve heard that idea before somewhere&#8230;  It&#8217;s too bad we don&#8217;t have virtual constructors, but in the meantime: you could add some static factory methods to the derived Shape classes.  Then, you could replace that switch statement with a map from ShapeNames to ShapeFactory Methods.  You would end up with something like this:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">delegate</span> <span style="color:#2b91af;">Shape</span> <span style="color:#2b91af;">ShapeFactoryMethod</span>();</p>
<p style="margin:0;"> </p>
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Circle</span> : <span style="color:#2b91af;">Shape</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">Shape</span> CreateObject()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Circle</span>();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
<p style="margin:0;"> </p>
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Square</span> : <span style="color:#2b91af;">Shape</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">Shape</span> CreateObject()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Square</span>();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
<p style="margin:0;"> </p>
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">ShapeFactory</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#2b91af;">ShapeName</span>, <span style="color:#2b91af;">ShapeFactoryMethod</span>&gt; map = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#2b91af;">ShapeName</span>, <span style="color:#2b91af;">ShapeFactoryMethod</span>&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Shape</span> CreateObject(<span style="color:#2b91af;">ShapeName</span> shapeName)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> map[shapeName]();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Register(<span style="color:#2b91af;">ShapeName</span> shapeName, <span style="color:#2b91af;">ShapeFactoryMethod</span> shapeFactoryMethod)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        map.Add(shapeName, shapeFactoryMethod);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">bool</span> Unregister(<span style="color:#2b91af;">ShapeName</span> shapeName)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> map.Remove(shapeName);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>That&#8217;s pretty cool, we got rid of the switch statement.  Now you don&#8217;t have to crack open the ShapeFactory.cs file for every additional shape you add, but somewhere you still need to instantiate a ShapeFactory and populate its map with shapes types.  We haven&#8217;t solved the problem yet, just moved it:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Program</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">ShapeFactory</span> shapeFactory = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">ShapeFactory</span>();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> CreateShapeFactory()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        shapeFactory.Register(<span style="color:#2b91af;">ShapeName</span>.Circle, <span style="color:#2b91af;">Circle</span>.CreateObject);</p>
<p style="margin:0;">        shapeFactory.Register(<span style="color:#2b91af;">ShapeName</span>.Square, <span style="color:#2b91af;">Square</span>.CreateObject);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>We still have two places to change every time we want to add another shape type.  It would be really nice if we could just add a static constructor to each class derived Shape that would automatically register itself with a static ShapeFactory like this:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Circle</span> : <span style="color:#2b91af;">Shape</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">static</span> Circle()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">ShapeFactory</span>.Register(<span style="color:#2b91af;">ShapeName</span>.Circle, <span style="color:#2b91af;">Circle</span>.CreateObject);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">Shape</span> CreateObject()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Circle</span>();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>Unfortunately .NET doesn&#8217;t play that way.  A class&#8217;s Static constructor is not called until the first time a method of that class is called.  To my knowledge, there is nothing in C# that is equivalent to the static scope initialization of C++.  However, there is something C# has that may still be useful: reflection.  In preparation, let&#8217;s add a little searchable identifier to each class that&#8217;s derived from shape.  Like this:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Circle</span> : <span style="color:#2b91af;">Shape</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">ShapeName</span> ShapeName</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">get</span> { <span style="color:#0000ff;">return</span> <span style="color:#2b91af;">ShapeName</span>.Circle; }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">Shape</span> CreateObject()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Circle</span>();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>Now let&#8217;s use a little reflection in the ShapeFactory to automatically load up its map:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">ShapeFactory</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#2b91af;">ShapeName</span>, ShapeFactoryMethod&gt; map = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#2b91af;">ShapeName</span>, ShapeFactoryMethod&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> ShapeFactory()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">Type</span>[] shapeTypes = <span style="color:#2b91af;">Assembly</span>.GetAssembly(<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)).GetTypes();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">        <span style="color:#0000ff;">foreach</span> (<span style="color:#2b91af;">Type</span> shapeType <span style="color:#0000ff;">in</span> shapeTypes)</p>
<p style="margin:0;">        {</p>
<p style="margin:0;">            <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>).IsAssignableFrom(shapeType) || shapeType == <span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)) <span style="color:#008000;">// if (shapeType is not derived from Shape)</span></p>
<p style="margin:0;">            {</p>
<p style="margin:0;">                <span style="color:#0000ff;">continue</span>; <span style="color:#008000;">// this type isn&#8217;t a Shape type, keep searching through the the assembly</span></p>
<p style="margin:0;">            }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Get the name of the shape type.</span></p>
<p style="margin:0;">            <span style="color:#2b91af;">PropertyInfo</span> propertyInfo = shapeType.GetProperty(<span style="color:#a31515;">&#8220;ShapeName&#8221;</span>);</p>
<p style="margin:0;">            <span style="color:#2b91af;">Debug</span>.Assert(propertyInfo != <span style="color:#0000ff;">null</span>, <span style="color:#a31515;">&#8220;ShapeName property not implemented for shape type: &#8220;</span> + shapeType.Name);</p>
<p style="margin:0;">            <span style="color:#2b91af;">ShapeName</span> shapeName = (<span style="color:#2b91af;">ShapeName</span>)propertyInfo.GetValue(<span style="color:#0000ff;">null</span>, <span style="color:#0000ff;">null</span>); <span style="color:#008000;">// shapeName = shapeType.ShapeName;</span></p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Get the static factory method of the shape type.</span></p>
<p style="margin:0;">            <span style="color:#2b91af;">MethodInfo</span> methodInfo = shapeType.GetMethod(<span style="color:#a31515;">&#8220;CreateObject&#8221;</span>);</p>
<p style="margin:0;">            <span style="color:#2b91af;">Debug</span>.Assert(methodInfo != <span style="color:#0000ff;">null</span>, <span style="color:#a31515;">&#8220;Factory method not implemented for shape type: &#8220;</span> + shapeType.Name);</p>
<p style="margin:0;">            <span style="color:#2b91af;">Delegate</span> shapeFactoryMethod = <span style="color:#2b91af;">Delegate</span>.CreateDelegate(<span style="color:#0000ff;">typeof</span>(ShapeFactoryMethod), methodInfo);</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Automatically register the shape type.</span></p>
<p style="margin:0;">            map.Add(shapeName, (ShapeFactoryMethod)shapeFactoryMethod);</p>
<p style="margin:0;">        }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Shape</span> CreateObject(<span style="color:#2b91af;">ShapeName</span> shapeName)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> map[shapeName]();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>We just got rid of the need to manually maintain the ShapeFactory&#8217;s list of shapes.  Pretty cool so far.  Now, what about that enumeration?  Let&#8217;s throw a little more reflection code at the problem:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">ShapeFactory</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, ShapeFactoryMethod&gt; map = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, ShapeFactoryMethod&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> ShapeFactory()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">Type</span>[] shapeTypes = <span style="color:#2b91af;">Assembly</span>.GetAssembly(<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)).GetTypes();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">        <span style="color:#0000ff;">foreach</span> (<span style="color:#2b91af;">Type</span> shapeType <span style="color:#0000ff;">in</span> shapeTypes)</p>
<p style="margin:0;">        {</p>
<p style="margin:0;">            <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>).IsAssignableFrom(shapeType) || shapeType == <span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)) <span style="color:#008000;">// if (shapeType is not derived from Shape)</span></p>
<p style="margin:0;">            {</p>
<p style="margin:0;">                <span style="color:#0000ff;">continue</span>; <span style="color:#008000;">// this type isn&#8217;t a Shape type, keep searching through the the assembly</span></p>
<p style="margin:0;">            }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Get the static factory method of the shape type.</span></p>
<p style="margin:0;">            <span style="color:#2b91af;">MethodInfo</span> methodInfo = shapeType.GetMethod(<span style="color:#a31515;">&#8220;CreateObject&#8221;</span>);</p>
<p style="margin:0;">            <span style="color:#2b91af;">Debug</span>.Assert(methodInfo != <span style="color:#0000ff;">null</span>, <span style="color:#a31515;">&#8220;Factory method not implemented for shape type: &#8220;</span> + shapeType.Name);</p>
<p style="margin:0;">            <span style="color:#2b91af;">Delegate</span> shapeFactoryMethod = <span style="color:#2b91af;">Delegate</span>.CreateDelegate(<span style="color:#0000ff;">typeof</span>(ShapeFactoryMethod), methodInfo);</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Automatically register the shape type.</span></p>
<p style="margin:0;">            map.Add(shapeType.Name, (ShapeFactoryMethod)shapeFactoryMethod);</p>
<p style="margin:0;">        }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Shape</span> CreateObject(<span style="color:#0000ff;">string</span> shapeName)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> map[shapeName]();</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>So the enumeration is gone AND you can even ditch the ShapeName property attached to each Shape class.  Now, if you want to add a Triangle class all you need to do is drop in your Triangle.cs source file and you won&#8217;t have need to modified existing code.  Sweet!  The only thing you have to remember to do is include a CreateObject() method on each new shape.  But wait!  Reflection can help us here too:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">ShapeFactory</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, <span style="color:#2b91af;">Type</span>&gt; map = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, <span style="color:#2b91af;">Type</span>&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> ShapeFactory()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">Type</span>[] shapeTypes = <span style="color:#2b91af;">Assembly</span>.GetAssembly(<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)).GetTypes();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">        <span style="color:#0000ff;">foreach</span> (<span style="color:#2b91af;">Type</span> shapeType <span style="color:#0000ff;">in</span> shapeTypes)</p>
<p style="margin:0;">        {</p>
<p style="margin:0;">            <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>).IsAssignableFrom(shapeType) || shapeType == <span style="color:#0000ff;">typeof</span>(<span style="color:#2b91af;">Shape</span>)) <span style="color:#008000;">// if (shapeType is not derived from Shape)</span></p>
<p style="margin:0;">            {</p>
<p style="margin:0;">                <span style="color:#0000ff;">continue</span>; <span style="color:#008000;">// this type isn&#8217;t a Shape type, keep searching through the the assembly</span></p>
<p style="margin:0;">            }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Automatically register the shape type.</span></p>
<p style="margin:0;">            map.Add(shapeType.Name, shapeType);</p>
<p style="margin:0;">        }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> <span style="color:#2b91af;">Shape</span> CreateObject(<span style="color:#0000ff;">string</span> shapeName, <span style="color:#0000ff;">params</span> <span style="color:#0000ff;">object</span>[] args)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> (<span style="color:#2b91af;">Shape</span>)<span style="color:#2b91af;">Activator</span>.CreateInstance(map[shapeName], args);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>Now we don&#8217;t have any special requirements of new Shape classes, we&#8217;ve ditched the extra factory method delegate, AND we can even use the most appropriate constructor for each object.  The only left to do is turn this factory into a library that works on any class hierarchy.  Let&#8217;s make it generic:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Factory</span>&lt;Product&gt;</p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">private</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, <span style="color:#2b91af;">Type</span>&gt; map = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Dictionary</span>&lt;<span style="color:#0000ff;">string</span>, <span style="color:#2b91af;">Type</span>&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> Factory()</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">Type</span>[] types = <span style="color:#2b91af;">Assembly</span>.GetAssembly(<span style="color:#0000ff;">typeof</span>(Product)).GetTypes();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">        <span style="color:#0000ff;">foreach</span> (<span style="color:#2b91af;">Type</span> type <span style="color:#0000ff;">in</span> types)</p>
<p style="margin:0;">        {</p>
<p style="margin:0;">            <span style="color:#0000ff;">if</span> (!<span style="color:#0000ff;">typeof</span>(Product).IsAssignableFrom(type) || type == <span style="color:#0000ff;">typeof</span>(Product)) <span style="color:#008000;">// if (type is not derived from Product)</span></p>
<p style="margin:0;">            {</p>
<p style="margin:0;">                <span style="color:#0000ff;">continue</span>; <span style="color:#008000;">// this type isn&#8217;t a Product type, keep searching through the the assembly</span></p>
<p style="margin:0;">            }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">            <span style="color:#008000;">// Automatically register the Product type.</span></p>
<p style="margin:0;">            map.Add(type.Name, type);</p>
<p style="margin:0;">        }</p>
<p style="margin:0;">    }</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">public</span> Product CreateObject(<span style="color:#0000ff;">string</span> productName, <span style="color:#0000ff;">params</span> <span style="color:#0000ff;">object</span>[] args)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#0000ff;">return</span> (Product)<span style="color:#2b91af;">Activator</span>.CreateInstance(map[productName], args);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>And this is how we&#8217;d use it as a Shape factory:</p>
<div style="font-size:10pt;background:white;color:black;font-family:courier new;">
<p style="margin:0;"><span style="color:#0000ff;">class</span> <span style="color:#2b91af;">Program</span></p>
<p style="margin:0;">{</p>
<p style="margin:0;">    <span style="color:#0000ff;">static</span> <span style="color:#2b91af;">Factory</span>&lt;<span style="color:#2b91af;">Shape</span>&gt; shapeFactory = <span style="color:#0000ff;">new</span> <span style="color:#2b91af;">Factory</span>&lt;<span style="color:#2b91af;">Shape</span>&gt;();</p>
<p style="margin:0;"> </p>
<p style="margin:0;">    <span style="color:#0000ff;">static</span> <span style="color:#0000ff;">void</span> Main(<span style="color:#0000ff;">string</span>[] args)</p>
<p style="margin:0;">    {</p>
<p style="margin:0;">        <span style="color:#2b91af;">Shape</span> s1 = shapeFactory.CreateObject(<span style="color:#a31515;">&#8220;Circle&#8221;</span>);</p>
<p style="margin:0;">        <span style="color:#2b91af;">Shape</span> s2 = shapeFactory.CreateObject(<span style="color:#a31515;">&#8220;Square&#8221;</span>);</p>
<p style="margin:0;">    }</p>
<p style="margin:0;">}</p>
</div>
<p>Now you&#8217;ve got a generic factory library in C# &#8230;and there&#8217;s still plenty of room to trick it out in my next blog post.  In the meantime, you are probably aware that the factory pattern is commonly combined with the singleton pattern.  I would personally recommend this article on the subject: <a href="http://www.yoda.arachsys.com/csharp/singleton.html">http://www.yoda.arachsys.com/csharp/singleton.html</a></p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/tranxcoder.wordpress.com/57/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/tranxcoder.wordpress.com/57/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/57/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=57&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">cgassib</media:title>
		</media:content>
	</item>
		<item>
		<title>Testing a Task</title>
		<link>http://tranxcoder.wordpress.com/2008/07/04/testing-a-task/</link>
		<comments>http://tranxcoder.wordpress.com/2008/07/04/testing-a-task/#comments</comments>
		<pubDate>Fri, 04 Jul 2008 21:20:29 +0000</pubDate>
		<dc:creator>hempelcx</dc:creator>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[MSBuild]]></category>
		<category><![CDATA[Unit Testing]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://tranxcoder.wordpress.com/2008/07/04/testing-a-task/</guid>
		<description><![CDATA[In my previous post I described the creation of a custom MSBuild task to aid in building WiX projects under TFS. However, one thing I have always disliked about most of the code nuggets found on blogs and magazine articles, which I find highly inexcusable in today&#8217;s development landscape, is that they rarely include any [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=51&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In my previous post I described the creation of a custom MSBuild task to aid in building WiX projects under TFS. However, one thing I have always disliked about <em>most</em> of the code nuggets found on blogs and magazine articles, which I find highly inexcusable in today&#8217;s development landscape, is that they rarely include any tests to prove that their code actually works. Therefore, this post is intended to demonstrate that throwing in a few simple unit tests with code samples is easy <em>and</em> goes a long way toward helping readers understand and trust the code being published.</p>
<p><span id="more-51"></span>The first thing that needs to be addressed in this case is the fact that the Software Under Test (SUT) is actually an extension for a third-party application &#8211; the MSBuild engine. For someone new to unit testing, that may seem like an insurmountable hurdle, after all I certainly don&#8217;t want to have to invoke the entire build framework in order to unit test my 188 line custom task. Fortunately some smart people have already shown us that an easy way to deal with those scenarios is to introduce a &#8220;test double&#8221;, the options and vocabulary of which are well explained by Martin Fowler <a title="Mocks Aren't Stubs" href="http://martinfowler.com/articles/mocksArentStubs.html" target="_blank">in this article</a>.
</p>
<p>While mock objects enable a deep level of testing and behavior assurance, manually creating them can be tedious depending on the object being mocked and the number of behavioral combinations involved. To help with that, many developers resort to frameworks such as <a title="typeock.com" href="http://www.typemock.com/" target="_blank">TypeMock</a>, <a title="Ayende @ Rahien - Rhino Mocks" href="http://www.ayende.com/projects/rhino-mocks.aspx" target="_blank">Rhino Mocks</a>, <a title="moq - Google Code" href="http://code.google.com/p/moq/" target="_blank">Moq</a>, et al. Of those, TypeMock has the distinction of using aspect-oriented techniques to actually redirect calls from the real code allowing you to test units which are otherwise difficult or impossible to isolate. Fortunately, in this particular case we have some nice interfaces to work against and I&#8217;m not especially concerned about guaranteeing internal behavior of my code, so I will make use of a simple stub object and focus on validating known inputs against expected outcomes.</p>
<p>Since the SUT is targeting Team Build I&#8217;m going to stay in that arena and use the testing tools built into Visual Studio Team System 2008 Development Edition for this sample. However, the code and concepts could easily be adapted (in many cases with no change) to work in <a title="NUnit - Home" href="http://www.nunit.org/index.php" target="_blank">NUnit</a>, <a title="MbUnit - Generative Unit Test Framework for the .NET Framework" href="http://www.mbunit.com/" target="_blank">MbUnit</a>, or even <a title="xUnit.net - Unit Testing for .NET" href="http://www.codeplex.com/xunit" target="_blank">xUnit.net</a>. All of which can be integrated into Visual Studio either natively or via <a title="TestDriven.NET &gt; Home" href="http://www.testdriven.net/" target="_blank">TestDriven.NET</a>.</p>
<p>For this post I&#8217;m only going to include two tests, each of which proves that a valid input produces the expected result. What is missing from a thorough test suite is the slew of exception cases which should also be covered. For instance, what happens when an invalid input is applied, or when the environment doesn&#8217;t meet preconditions, etc. However, those tests are actually easier to write and for the sake of brevity I&#8217;ll leave them to the reader.</p>
<p>The first thing I did is create a new project in the build task solution called WixVarSubstitutionTests (there are many varied opinions on the pros and cons of separating tests from code, but at Tranxition we&#8217;ve decided to adopt that approach so I&#8217;m using it here.) Next add a project reference to the WixVarSubstitution project and make sure references are also present for Microsoft.Build.Framework, Microsoft.Build.Utilities.v3.5, and System.Xml.Linq. Finally, create a new C# class called WixVarSubstitutionTaskTest and we&#8217;re ready to write some tests.</p>
<p>Now that we&#8217;re ready to write some code, we need to build up a bit of infrastructure to enable our test methods. All test &#8220;fixtures&#8221; need to be adorned with the TestClassAttribute, and we&#8217;ll need to initialize a task instance for each test method:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray 0 0;color:white;">18</span> [<span style="color:#a65300;">TestClass</span>()]</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">19</span> <span style="color:navy;">public</span> <span style="color:navy;">class</span> <span style="color:#a65300;">WixVarSubstitutionTest</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">20</span> {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">21</span>&nbsp;&nbsp; <span style="color:#a65300;">WixVarSubstitution</span> <span style="color:maroon;">_task</span>;</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">22</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">23</span>&nbsp;&nbsp; [<span style="color:#a65300;">TestInitialize</span>()]</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">24</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">TestInitialize</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">25</span>&nbsp;&nbsp; {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">26</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:maroon;">_task</span> = <span style="color:navy;">new</span> <span style="color:#a65300;">WixVarSubstitution</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">27</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">BuildEngine</span> = <span style="color:navy;">new</span> <span style="color:#a65300;">BuildEngineStub</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">28</span>&nbsp;&nbsp; }</p>
</div>
<p>Notice the <span style="color:#a65300;">BuildEngineStub</span> reference? That is a stub object (test double) which we&#8217;ll use to isolate our task from the actual MSBuild engine. So the only thing left to do before writing our tests is to create that stub class:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray 0 0;color:white;">147</span> <span style="color:navy;">private</span> <span style="color:navy;">class</span> <span style="color:#a65300;">BuildEngineStub</span> : <span style="color:#2b91af;">IBuildEngine</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">148</span> {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">149</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">bool</span> <span style="color:maroon;">BuildProjectFile</span>(</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">150</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">string</span> <span style="color:maroon;">projectFileName</span>, <span style="color:navy;">string</span>[] <span style="color:maroon;">targetNames</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">151</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:#2b91af;">IDictionary</span> <span style="color:maroon;">globalProperties</span>, <span style="color:#2b91af;">IDictionary</span> <span style="color:maroon;">targetOutputs</span> ) { <span style="color:navy;">return</span> <span style="color:navy;">true</span>; }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">152</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">153</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">bool</span> <span style="color:maroon;">ContinueOnError</span> { <span style="color:navy;">get</span> { <span style="color:navy;">return</span> <span style="color:navy;">false</span>; } }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">154</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">155</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">int</span> <span style="color:maroon;">ColumnNumberOfTaskNode</span> { <span style="color:navy;">get</span> { <span style="color:navy;">return</span> <span style="background:#e6ffff;">0</span>; } }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">156</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">157</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">int</span> <span style="color:maroon;">LineNumberOfTaskNode</span> { <span style="color:navy;">get</span> { <span style="color:navy;">return</span> <span style="background:#e6ffff;">0</span>; } }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">158</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">159</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">string</span> <span style="color:maroon;">ProjectFileOfTaskNode</span> { <span style="color:navy;">get</span> { <span style="color:navy;">return</span> <span style="color:navy;">string</span>.<span style="color:maroon;">Empty</span>; } }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">160</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">161</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">LogCustomEvent</span>( <span style="color:#a65300;">CustomBuildEventArgs</span> <span style="color:maroon;">e</span> ) { <span style="color:navy;">return</span>; }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">162</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">163</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">LogErrorEvent</span>( <span style="color:#a65300;">BuildErrorEventArgs</span> <span style="color:maroon;">e</span> ) { <span style="color:navy;">return</span>; }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">164</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">165</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">LogMessageEvent</span>( <span style="color:#a65300;">BuildMessageEventArgs</span> <span style="color:maroon;">e</span> ) { <span style="color:navy;">return</span>; }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">166</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">167</span>&nbsp;&nbsp; <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">LogWarningEvent</span>( <span style="color:#a65300;">BuildWarningEventArgs</span> <span style="color:maroon;">e</span> ) { <span style="color:navy;">return</span>; }</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">168</span> }</p>
</div>
<p>Obviously, this stub doesn&#8217;t do a whole lot. That&#8217;s actually the point of a stub, to do as little as possible while providing properties and methods for the supported interfaces. In this case, the only interface we need to implement is <a title="IBuildEngine Interface (Microsoft.Build.Framework)" href="http://msdn.microsoft.com/en-us/library/microsoft.build.framework.ibuildengine.aspx" target="_blank">IBuildEngine</a>.</p>
<p>One issue you may run into occasionally with stub objects is that the method or property implementation provided causes behavioral issues somewhere down the line. For instance, originally I had the read-only property <span style="color:maroon;">ProjectFileOfTaskNode</span> return a null reference, however, during testing I discovered that the base <a title="Task Class (Microsoft.Build.Utilities)" href="http://msdn.microsoft.com/en-us/library/microsoft.build.utilities.task.aspx" target="_blank">Task</a> class doesn&#8217;t support that and will throw an exception under certain scenarios. So I simply changed the return to an empty string and the problem went away. Just be aware that this is one of the known limitations with simple stub objects.</p>
<p>Because both of my test methods are going to need a temp file containing some pre-defined XML, I&#8217;ll use a helper method to set that up each time:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray 0 0;color:white;">126</span> <span style="color:navy;">private</span> <span style="color:navy;">static</span> <span style="color:navy;">string</span> <span style="color:maroon;">PrepTestFile</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">127</span> {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">128</span>&nbsp;&nbsp; <span style="color:navy;">string</span> <span style="color:maroon;">tempFilePath</span> = <span style="color:#a65300;">Path</span>.<span style="color:maroon;">GetTempFileName</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">129</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">130</span>&nbsp;&nbsp; <span style="color:green;">// Create a sample XML document and save it to the temp file</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">131</span>&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XDocument</span>(</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">132</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XDeclaration</span>( <span style="color:#a31515;">@&#8221;1.0&#8243;</span>, <span style="color:#a31515;">@&#8221;windows-1252&#8243;</span>, <span style="background:#ffffe6;">&#8220;yes&#8221;</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">133</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;Include&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">134</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XProcessingInstruction</span>( <span style="background:#ffffe6;">&#8220;define&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var1 = \&#8221;Var1Value\&#8221;"</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">135</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XProcessingInstruction</span>( <span style="background:#ffffe6;">&#8220;define&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var2 = \&#8221;Var2Value\&#8221;"</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">136</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XProcessingInstruction</span>( <span style="background:#ffffe6;">&#8220;define&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var3=\&#8221;Var3Value\&#8221;"</span> )</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">137</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">138</span>&nbsp;&nbsp; ).<span style="color:maroon;">Save</span>( <span style="color:maroon;">tempFilePath</span>, <span style="color:#2b91af;">SaveOptions</span>.<span style="color:maroon;">None</span> );</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">139</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">140</span>&nbsp;&nbsp; <span style="color:navy;">return</span> <span style="color:maroon;">tempFilePath</span>;</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">141</span> }</p>
</div>
<p>The call to <a title="Path.GetTempFileName Method (System.IO)" href="http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx" target="_blank">Path.GetTempFileName</a> actually creates an empty file in the current user&#8217;s temporary files folder and returns the full path as a string. Then a simple <a title="XDocument Class (System.Xml.Linq)" href="http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.aspx" target="_blank">XDocument</a> instance is built up using the convenient construction syntax. And finally the constructed XDocument is saved into the new temp.</p>
<p>At last we&#8217;ve reached the actual code for our test methods. The first just validates that when a single VariableDefinition is provided, that variable&#8217;s value in the XML file is correctly modified:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray 0 0;color:white;">59</span> [<span style="color:#a65300;">TestMethod</span>()]</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">60</span> <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">WixVarSubstitutionTaskTestExecuteWorksGivenOneVariableDefinition</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">61</span> {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">62</span>&nbsp;&nbsp; <span style="color:green;">// Set the SourceFile property to point to the temp file</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">63</span>&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">SourceFile</span> = <span style="color:maroon;">PrepTestFile</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">64</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">65</span>&nbsp;&nbsp; <span style="color:green;">// Set the VariableDefinitions to effect one of the three variables</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">66</span>&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">VariableDefinitions</span> =</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">67</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;Root&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">68</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;VariableDefinition&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">69</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;Name&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var1&#8243;</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">70</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;NewValue&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var1NewValue&#8221;</span> ) )</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">71</span>&nbsp;&nbsp;&nbsp;&nbsp; ).<span style="color:maroon;">ToString</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">72</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">73</span>&nbsp;&nbsp; <span style="color:green;">// Execute the _task</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">74</span>&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">Execute</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">75</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">76</span>&nbsp;&nbsp; <span style="color:green;">// Load in and process the temp file</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">77</span>&nbsp;&nbsp; <span style="color:navy;">var</span> <span style="color:maroon;">e</span> = <span style="color:navy;">from</span> <span style="color:maroon;">n</span> <span style="color:navy;">in</span> <span style="color:#a65300;">XDocument</span>.<span style="color:maroon;">Load</span>( <span style="color:maroon;">_task</span>.<span style="color:maroon;">SourceFile</span>, <span style="color:#2b91af;">LoadOptions</span>.<span style="color:maroon;">PreserveWhitespace</span> ).<span style="color:maroon;">DescendantNodes</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">78</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">where</span> <span style="color:maroon;">n</span>.<span style="color:maroon;">NodeType</span> == <span style="color:#2b91af;">XmlNodeType</span>.<span style="color:maroon;">ProcessingInstruction</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">79</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; ( (<span style="color:#a65300;">XProcessingInstruction</span>) <span style="color:maroon;">n</span> ).<span style="color:maroon;">Target</span> == <span style="background:#ffffe6;">&#8220;define&#8221;</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">80</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">select</span> <span style="color:maroon;">n</span> <span style="color:navy;">as</span> <span style="color:#a65300;">XProcessingInstruction</span>;</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">81</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">82</span>&nbsp;&nbsp; <span style="color:green;">// Verify that Var1 was changed as expected</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">83</span>&nbsp;&nbsp; <span style="color:green;">// Using a regex to ignore insignificant whitespace</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">84</span>&nbsp;&nbsp; <span style="color:#a65300;">Assert</span>.<span style="color:maroon;">IsTrue</span>( <span style="color:#a65300;">Regex</span>.<span style="color:maroon;">IsMatch</span>( <span style="color:maroon;">e</span>.<span style="color:maroon;">First</span>( <span style="color:maroon;">pi</span> =&gt; <span style="color:maroon;">pi</span>.<span style="color:maroon;">Data</span>.<span style="color:maroon;">StartsWith</span>( <span style="background:#ffffe6;">&#8220;Var1&#8243;</span> ) ).<span style="color:maroon;">Data</span>, <span style="background:#ffffe6;">&#8220;Var1\\s*=\\s*\&#8221;Var1NewValue\&#8221;"</span> ) );</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">85</span> }</p>
</div>
<p>That test follows the common four-stage testing pattern:</p>
<ol>
<li>Set up prerequisite objects
<li>Call the method being tested<br />_task.Execute()
<li>Evaluate the results<br />Load the temp file as an XDocument, retrieve the Processing Instructions, and assert that the value for the &#8220;Var1&#8243; variable was changed.
<li>Tear down the objects </li>
</ol>
<p>The implicit step in there is #4, obviously, since we&#8217;re just allowing the garbage collector to handle object tear-down. It would probably be preferable to delete the temp file explicitly rather than letting it hang around after the test ends.</p>
<p>Now we have a test for providing a single variable definition, the next test will do the same but for providing multiple definitions:</p>
<div style="font-size:10pt;background:#f8f8f8;color:black;font-family:consolas;">
<p style="margin:0;"><span style="background:gray 0 0;color:white;">87</span> [<span style="color:#a65300;">TestMethod</span>()]</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">88</span> <span style="color:navy;">public</span> <span style="color:navy;">void</span> <span style="color:maroon;">WixVarSubstitutionTaskTestExecuteWorksGivenMultipleVariableDefinitions</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">89</span> {</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">90</span>&nbsp;&nbsp; <span style="color:green;">// Set the SourceFile property to point to the temp file</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">91</span>&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">SourceFile</span> = <span style="color:maroon;">PrepTestFile</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">92</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">93</span>&nbsp;&nbsp; <span style="color:green;">// Set the VariableDefinitions to effect two of the three variables</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">94</span>&nbsp;&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">VariableDefinitions</span> =</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">95</span>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;Root&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">96</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;VariableDefinition&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">97</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;Name&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var1&#8243;</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">98</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;NewValue&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var1NewValue&#8221;</span> ) ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">99</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XElement</span>( <span style="background:#ffffe6;">&#8220;VariableDefinition&#8221;</span>,</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">100</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;Name&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var3&#8243;</span> ),</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">101</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color:navy;">new</span> <span style="color:#a65300;">XAttribute</span>( <span style="background:#ffffe6;">&#8220;NewValue&#8221;</span>, <span style="background:#ffffe6;">&#8220;Var3NewValue&#8221;</span> ) )</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">102</span>&nbsp;&nbsp;&nbsp; ).<span style="color:maroon;">ToString</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">103</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">104</span>&nbsp; <span style="color:green;">// Execute the _task</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">105</span>&nbsp; <span style="color:maroon;">_task</span>.<span style="color:maroon;">Execute</span>();</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">106</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">107</span>&nbsp; <span style="color:green;">// Load in and process the temp file</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">108</span>&nbsp; <span style="color:navy;">var</span> <span style="color:maroon;">e</span> = <span style="color:navy;">from</span> <span style="color:maroon;">n</span> <span style="color:navy;">in</span> <span style="color:#a65300;">XDocument</span>.<span style="color:maroon;">Load</span>( <span style="color:maroon;">_task</span>.<span style="color:maroon;">SourceFile</span>, <span style="color:#2b91af;">LoadOptions</span>.<span style="color:maroon;">PreserveWhitespace</span> ).<span style="color:maroon;">DescendantNodes</span>()</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">109</span>&nbsp;&nbsp;&nbsp; <span style="color:navy;">where</span> <span style="color:maroon;">n</span>.<span style="color:maroon;">NodeType</span> == <span style="color:#2b91af;">XmlNodeType</span>.<span style="color:maroon;">ProcessingInstruction</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">110</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;&amp; ( (<span style="color:#a65300;">XProcessingInstruction</span>) <span style="color:maroon;">n</span> ).<span style="color:maroon;">Target</span> == <span style="background:#ffffe6;">&#8220;define&#8221;</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">111</span>&nbsp;&nbsp;&nbsp; <span style="color:navy;">select</span> <span style="color:maroon;">n</span> <span style="color:navy;">as</span> <span style="color:#a65300;">XProcessingInstruction</span>;</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">112</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">113</span>&nbsp; <span style="color:green;">// Verify that Var1 and Var3 where changed as expected</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">114</span>&nbsp; <span style="color:green;">// Using a regex to ignore insignificant whitespace</span></p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">115</span>&nbsp; <span style="color:#a65300;">Assert</span>.<span style="color:maroon;">IsTrue</span>( <span style="color:#a65300;">Regex</span>.<span style="color:maroon;">IsMatch</span>( <span style="color:maroon;">e</span>.<span style="color:maroon;">First</span>( <span style="color:maroon;">pi</span> =&gt; <span style="color:maroon;">pi</span>.<span style="color:maroon;">Data</span>.<span style="color:maroon;">StartsWith</span>( <span style="background:#ffffe6;">&#8220;Var1&#8243;</span> ) ).<span style="color:maroon;">Data</span>, <span style="background:#ffffe6;">&#8220;Var1\\s*=\\s*\&#8221;Var1NewValue\&#8221;"</span> ) );</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">116</span>&nbsp; <span style="color:#a65300;">Assert</span>.<span style="color:maroon;">IsTrue</span>( <span style="color:#a65300;">Regex</span>.<span style="color:maroon;">IsMatch</span>( <span style="color:maroon;">e</span>.<span style="color:maroon;">First</span>( <span style="color:maroon;">pi</span> =&gt; <span style="color:maroon;">pi</span>.<span style="color:maroon;">Data</span>.<span style="color:maroon;">StartsWith</span>( <span style="background:#ffffe6;">&#8220;Var3&#8243;</span> ) ).<span style="color:maroon;">Data</span>, <span style="background:#ffffe6;">&#8220;Var3\\s*=\\s*\&#8221;Var3NewValue\&#8221;"</span> ) );</p>
<p style="margin:0;"><span style="background:gray 0 0;color:white;">117</span> }</p>
</div>
<p>And of course writing tests is not particularly useful if you don&#8217;t ever run them:</p>
<p><a href="http://tranxcoder.files.wordpress.com/2008/07/image.png"><img style="border-width:0;" border="0" alt="image" src="http://tranxcoder.files.wordpress.com/2008/07/image-thumb.png?w=484&#038;h=92" width="484" height="92"></a></p>
<p>There are lots of additional tests needed, so I&#8217;ll just throw out a few obvious ones:</p>
<ul>
<li>File is unaffected when one/multiple VariableDefinitions are supplied but no variable names match
<li>Expected result when SourceFile is marked readonly
<ul>
<li>This actually turned up a problem for us with the custom task which had to be resolved </li>
</ul>
<li>&#8220;&#8221; when SourceFile doesn&#8217;t exist
<li>&#8220;&#8221; when SourceFile doesn&#8217;t contain a valid XML document </li>
</ul>
<p>It may seem like it took a while getting there, but most of the infrastructure is actually provided for you by Visual Studio Team System if you right click on a class or method and select &#8220;Create Unit Tests&#8230;&#8221;. With a little practice, going from zero to 70% (or more) code coverage should take less than 15 minutes for most units of code. If it takes longer it may be worth refactoring your code or consider adopting a mocking framework to help take care of some of the manual set up.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/tranxcoder.wordpress.com/51/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/tranxcoder.wordpress.com/51/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/tranxcoder.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/tranxcoder.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/tranxcoder.wordpress.com/51/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=tranxcoder.wordpress.com&amp;blog=3688975&amp;post=51&amp;subd=tranxcoder&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://tranxcoder.wordpress.com/2008/07/04/testing-a-task/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">hemp</media:title>
		</media:content>

		<media:content url="http://tranxcoder.files.wordpress.com/2008/07/image-thumb.png" medium="image">
			<media:title type="html">image</media:title>
		</media:content>
	</item>
	</channel>
</rss>
