<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Pigs Can Fly : Source Code</title><link>http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx</link><description>Tags: Source Code</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>StackOverflow answer – why learn multi-core programming? #2</title><link>http://blogs.msdn.com/pigscanfly/archive/2009/08/06/stackoverflow-answer-why-learn-multi-core-programming-2.aspx</link><pubDate>Thu, 06 Aug 2009 20:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9859413</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/9859413.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=9859413</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=9859413</wfw:comment><description>&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/pigscanfly/archive/2009/03/30/stackoverflow-answer-why-learn-multi-core-programming.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/archive/2009/03/30/stackoverflow-answer-why-learn-multi-core-programming.aspx"&gt;last post&lt;/A&gt; I talked about how multi-threading can be used to improve responsiveness while loading a file.&amp;nbsp;&amp;nbsp;&amp;nbsp; I’ve put together a sample program (source included) that shows how to do this in C# 3.0, .NET 3.5, and WPF using Visual Studio 2008.&amp;nbsp; You can find a zip file with a complete project attached.&lt;/P&gt;
&lt;P&gt;The program has a very simple, but fully functional UI.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_4.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=BFE1 border=0 alt=BFE1 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_thumb_1.png" width=383 height=186 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE1_thumb_1.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The “Open a file…” pops up the standard open file dialog and ask the user to find a file.&amp;nbsp;&amp;nbsp; The cancel button is disabled unless there is a loading operation to cancel.&amp;nbsp; The text box is for messages from the loader thread and the slider is just there to show that the UI is responsive while the background load occurs.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_2.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_2.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=BFE2 border=0 alt=BFE2 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_thumb.png" width=386 height=184 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/StackOverflowanswerwhylearnmulticoreprog_ED8A/BFE2_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The progress bar is hidden unless a file is actually being loaded.&amp;nbsp; If the async check box is un-checked, then the file will be loaded synchronously.&amp;nbsp; This illustrates how the UI will ‘freeze’ if a second thread isn’t used.&lt;/P&gt;
&lt;P&gt;The key thing about this program is that the UI stays completely responsive while a file is loaded.&amp;nbsp; Of course, this can be done without threads – many programs are written using a state machine approach.&amp;nbsp; But using threads, and functional programming make this much more simple than previous approaches. &lt;/P&gt;
&lt;P&gt;There are many ways to leverage threads in managed code, but the most straight forward way is using the BackgroundWorker class.&amp;nbsp; IT can be used in two ways, by creating one and attaching functions to its delegates, or by creating a new class derived from BackgroundWorker – this is the approach I took here.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;I created a class called AsyncFileLoader that is derived from BackgroundWorker.&amp;nbsp; We’re using all the features of BackgroundWorker here&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Support for asynchronous progress notifications &lt;/LI&gt;
&lt;LI&gt;Support for cancelation &lt;/LI&gt;
&lt;LI&gt;Handling of errors during the file loading &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Progress and cancelation is enabled by setting their properties in the constructor.&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; AsyncFileLoader()&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     WorkerReportsProgress = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;     WorkerSupportsCancellation = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;We also need an event handler that will be connected to the cancel button&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; PerformCancel( &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; sender,  RoutedEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.CancelAsync();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;The final element is a function that overrides BackgroundWorker.OnDoWork().&amp;nbsp;&amp;nbsp; This function does all the work of asynchronously loading a text file.&lt;/P&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;protected&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; OnDoWork( DoWorkEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// note: do not catch exceptions here.  The BackgroundWorker will catch exceptions &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// and pass them back to the initiating thread in the RunWorkerCompleted() delegate &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #008000"&gt;// using the error member of RunWorkerCompletedEventArgs parameter.&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum6&gt;   6:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum7&gt;   7:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; FileName = e.Argument &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum8&gt;   8:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum9&gt;   9:&lt;/SPAN&gt;     ReportProgress( &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue, String.Format( &lt;SPAN style="COLOR: #006080"&gt;"Opening {0}"&lt;/SPAN&gt;, FileName ) );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum10&gt;  10:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum11&gt;  11:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; ( StreamReader sr = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; StreamReader( FileName, Encoding.UTF8 ) ) &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum12&gt;  12:&lt;/SPAN&gt;     {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum13&gt;  13:&lt;/SPAN&gt;         ReportProgress( &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue, String.Format( &lt;SPAN style="COLOR: #006080"&gt;"Loading {0}"&lt;/SPAN&gt;, FileName ) );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum14&gt;  14:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum15&gt;  15:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; FileLength = sr.BaseStream.Length;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum16&gt;  16:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; PercentRead = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum17&gt;  17:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;long&lt;/SPAN&gt; LastPercentRead = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum18&gt;  18:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum19&gt;  19:&lt;/SPAN&gt;         String line;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum20&gt;  20:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum21&gt;  21:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;while&lt;/SPAN&gt; ( (line = sr.ReadLine()) != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt; ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum22&gt;  22:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum23&gt;  23:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( CancellationPending ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum24&gt;  24:&lt;/SPAN&gt;                 e.Cancel = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum25&gt;  25:&lt;/SPAN&gt;                 &lt;SPAN style="COLOR: #0000ff"&gt;break&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum26&gt;  26:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum27&gt;  27:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum28&gt;  28:&lt;/SPAN&gt;             PercentRead = (sr.BaseStream.Position * 100) / FileLength;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum29&gt;  29:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum30&gt;  30:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( PercentRead &amp;gt;= LastPercentRead + 1 ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum31&gt;  31:&lt;/SPAN&gt;                 ReportProgress( (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;)PercentRead );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum32&gt;  32:&lt;/SPAN&gt;                 LastPercentRead = PercentRead;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum33&gt;  33:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum34&gt;  34:&lt;/SPAN&gt;         }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum35&gt;  35:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum36&gt;  36:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;As you can see – this is really simple, and most important procedural – there isn’t a state machine, or any explicitly state kept at all.&amp;nbsp; This single function loads the file, and sends progress messages and errors asynchronously to the calling thread. &lt;/P&gt;
&lt;P&gt;The initiating thread passes the background thread parameters using the DoWorkEventArgs class.&amp;nbsp; Here, I’ve simply passed the file name as a string, but any class or structure could be passed this way.&lt;/P&gt;
&lt;P&gt;Line 9 is important – it asynchronously passes the first progress message back to the main thread.&amp;nbsp;&amp;nbsp; This includes the progress percentage and the name of the file.&amp;nbsp; Here I’m using &lt;STRONG&gt;int.MinValue&lt;/STRONG&gt; to differentiate the first progress message from subsequent ones.&amp;nbsp; This sentinel value means that the main thread doesn’t have to maintain any state to handle progress messages. &lt;/P&gt;
&lt;P&gt;I mentioned above that this function handles errors, but you don’t see any error handling code!&amp;nbsp; Any errors that occur from opening the file, or reading the data are signaled as exceptions.&amp;nbsp; The BackgroundWorker class will catch these and pass them back tot he main thread.&amp;nbsp; I just love this – it keeps the code here very clean.&lt;/P&gt;
&lt;P&gt;Note the using statement on line 11.&amp;nbsp; It is important to do this when using file I/O objects so the underlying OS objects get cleaned up correctly.&amp;nbsp; See &lt;A href="http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/system.idisposable.dispose.aspx"&gt;this&lt;/A&gt; for more information.&lt;/P&gt;
&lt;P&gt;The progress percentage value is computed very simply, the code simply keeps track of the file position as a ration to the file size.&amp;nbsp; This is the obvious part.&lt;/P&gt;
&lt;P&gt;Note line 30 – this is very important.&amp;nbsp; It only sends progress messages to the main thread when the value changes – not for every line, which would be quite expensive (give it a try to see).&lt;/P&gt;
&lt;P&gt;The entire AsyncFileLoader.cs file is not very big, only 29 lines of actual code and is very straightforward. &lt;/P&gt;
&lt;P&gt;The code in the main thread to mange the UI is equally straight forward and consists of just a single event handler attached to the open button’s click delegate.&amp;nbsp; This one function does all of the following:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Gets the file name from the user using the open file dialog. &lt;/LI&gt;
&lt;LI&gt;Maintains the UI state, disable buttons,&amp;nbsp; showing/hiding the progress bar, displaying messages, etc. &lt;/LI&gt;
&lt;LI&gt;Creates a the AsyncFileLoader object &lt;/LI&gt;
&lt;LI&gt;Starts the asynchronous file loading operation &lt;/LI&gt;
&lt;LI&gt;Handles progress messages &lt;/LI&gt;
&lt;LI&gt;handles the completion of the operation &lt;/LI&gt;
&lt;LI&gt;Handles errors. &lt;/LI&gt;&lt;/OL&gt;
&lt;DIV id=codeSnippetWrapper&gt;
&lt;DIV style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px" id=codeSnippet&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum1&gt;   1:&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; OpenAFile_Clicked( &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; sender, RoutedEventArgs e )&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum2&gt;   2:&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum3&gt;   3:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;try&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum4&gt;   4:&lt;/SPAN&gt;         OpenFileDialog ofd = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; OpenFileDialog();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum5&gt;   5:&lt;/SPAN&gt;         ofd.CheckFileExists = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum6&gt;   6:&lt;/SPAN&gt;         ofd.DefaultExt = &lt;SPAN style="COLOR: #006080"&gt;"txt"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum7&gt;   7:&lt;/SPAN&gt;         ofd.Title = &lt;SPAN style="COLOR: #006080"&gt;"Open an text File"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum8&gt;   8:&lt;/SPAN&gt;         ofd.Filter = &lt;SPAN style="COLOR: #006080"&gt;"Text|*.txt"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum9&gt;   9:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum10&gt;  10:&lt;/SPAN&gt;         OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum11&gt;  11:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum12&gt;  12:&lt;/SPAN&gt;         ofd.ShowDialog();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum13&gt;  13:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum14&gt;  14:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( ofd.FileName.IsBlank() ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum15&gt;  15:&lt;/SPAN&gt;             OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum16&gt;  16:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum17&gt;  17:&lt;/SPAN&gt;         }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum18&gt;  18:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum19&gt;  19:&lt;/SPAN&gt;         AsyncFileLoader TheLoader = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; AsyncFileLoader();&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum20&gt;  20:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum21&gt;  21:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Do this when the progress bar is updated&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum22&gt;  22:&lt;/SPAN&gt;         TheLoader.ProgressChanged += ( Sender, ArgsX ) =&amp;gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum23&gt;  23:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum24&gt;  24:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( ArgsX.ProgressPercentage == &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt;.MinValue ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum25&gt;  25:&lt;/SPAN&gt;                 Cancel_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum26&gt;  26:&lt;/SPAN&gt;                 Cancel_Button.Click += TheLoader.PerformCancel;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum27&gt;  27:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum28&gt;  28:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Visibility = Visibility.Visible;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum29&gt;  29:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Value = 0;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum30&gt;  30:&lt;/SPAN&gt;                 Info_TextBox.Text = ArgsX.UserState &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; String;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum31&gt;  31:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum32&gt;  32:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum33&gt;  33:&lt;/SPAN&gt;                 OpenProgress_ProgressBar.Value = ArgsX.ProgressPercentage;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum34&gt;  34:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum35&gt;  35:&lt;/SPAN&gt;         };&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum36&gt;  36:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum37&gt;  37:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Do this when the background worker is completed &lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum38&gt;  38:&lt;/SPAN&gt;         TheLoader.RunWorkerCompleted += ( SenderX, ArgsX ) =&amp;gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum39&gt;  39:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum40&gt;  40:&lt;/SPAN&gt;             RunWorkerCompletedEventArgs args = ArgsX &lt;SPAN style="COLOR: #0000ff"&gt;as&lt;/SPAN&gt; RunWorkerCompletedEventArgs;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum41&gt;  41:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum42&gt;  42:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( args.Error != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt; ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum43&gt;  43:&lt;/SPAN&gt;                 PopErrorDialog( args.Error, &lt;SPAN style="COLOR: #006080"&gt;"Cannot process file!"&lt;/SPAN&gt; );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum44&gt;  44:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum45&gt;  45:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum46&gt;  46:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ( args.Cancelled ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum47&gt;  47:&lt;/SPAN&gt;                 Info_TextBox.Text = &lt;SPAN style="COLOR: #006080"&gt;"Loading cancled"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum48&gt;  48:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum49&gt;  49:&lt;/SPAN&gt;             &lt;SPAN style="COLOR: #0000ff"&gt;else&lt;/SPAN&gt; {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum50&gt;  50:&lt;/SPAN&gt;                 Info_TextBox.Text = &lt;SPAN style="COLOR: #006080"&gt;"File Loaded"&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum51&gt;  51:&lt;/SPAN&gt;             }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum52&gt;  52:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum53&gt;  53:&lt;/SPAN&gt;             Cancel_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum54&gt;  54:&lt;/SPAN&gt;             Cancel_Button.Click -= TheLoader.PerformCancel;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum55&gt;  55:&lt;/SPAN&gt;             OpenProgress_ProgressBar.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum56&gt;  56:&lt;/SPAN&gt;             OpenProgress_ProgressBar.Visibility = Visibility.Hidden;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum57&gt;  57:&lt;/SPAN&gt;             OpenAFile_Button.IsEnabled = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum58&gt;  58:&lt;/SPAN&gt;         };&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum59&gt;  59:&lt;/SPAN&gt;&amp;nbsp; &lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum60&gt;  60:&lt;/SPAN&gt;         &lt;SPAN style="COLOR: #008000"&gt;//---- Start the ascynrnous file loading operation&lt;/SPAN&gt;&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum61&gt;  61:&lt;/SPAN&gt;         TheLoader.RunWorkerAsync( ofd.FileName );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum62&gt;  62:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum63&gt;  63:&lt;/SPAN&gt;     &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; ( Exception Ex ) {&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum64&gt;  64:&lt;/SPAN&gt;         PopErrorDialog( Ex, &lt;SPAN style="COLOR: #006080"&gt;"General Failure!"&lt;/SPAN&gt; );&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: white; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum65&gt;  65:&lt;/SPAN&gt;     }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;PRE style="BORDER-BOTTOM-STYLE: none; TEXT-ALIGN: left; PADDING-BOTTOM: 0px; LINE-HEIGHT: 12pt; BORDER-RIGHT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; MARGIN: 0em; PADDING-LEFT: 0px; WIDTH: 100%; PADDING-RIGHT: 0px; FONT-FAMILY: 'Courier New', courier, monospace; DIRECTION: ltr; BORDER-TOP-STYLE: none; COLOR: black; FONT-SIZE: 8pt; BORDER-LEFT-STYLE: none; OVERFLOW: visible; PADDING-TOP: 0px"&gt;&lt;SPAN style="COLOR: #606060" id=lnum66&gt;  66:&lt;/SPAN&gt; }&lt;/PRE&gt;&lt;!--CRLF--&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;DIV&gt;Functional programming is key to making this code clean and straight forward.&amp;nbsp;&amp;nbsp; Here we’re using lambda functions connected to the AsyncFileLoader’s progress and completion events.&lt;/DIV&gt;
&lt;P&gt;You can see in the progress changed handler how no state needs to be kept – this lambda function gets all the data it needs from the event.&amp;nbsp;&amp;nbsp; You can see how the sentinel value (int.MinValue) is used to trigger the change in UI state.&lt;/P&gt;
&lt;P&gt;Completion is handles in a similarly manner and resets the UI state.&amp;nbsp;&amp;nbsp; This lambda also handles any errors thrown by the loader by checking the args.Error member which will reference an exception if one was thrown.&lt;/P&gt;
&lt;P&gt;This is a great example of using multi-threaded programming for something other than speeding up a computationally bound algorithm using parallelization.&amp;nbsp;&amp;nbsp; Some may suggest that this isn’t “real multi-core” programming, but it is.&amp;nbsp; Indeed, the developer doesn’t need to know how to implement complex inter thread communication or synchronization, but just because this isn’t hard, doesn’t mean it isn’t real multi-threaded, and multi-core enabled code.&amp;nbsp; It absolutely is and the developer does need to understand asynchronous programming techniques to use it. &lt;/P&gt;
&lt;P&gt;Using the BackgroundWorker class is a very simple straight forward way to enable your programs to be more responsive, and to leverage multi-threaded and multi-core performance.&amp;nbsp;&amp;nbsp; You can use other managed code techniques such as threads and dispatching for more sophisticated work.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ef56a28c-723b-4ae1-8908-a387f076f35d class=wlWriterEditableSmartContent&gt;del.icio.us Tags: &lt;A href="http://del.icio.us/popular/performacne" rel=tag mce_href="http://del.icio.us/popular/performacne"&gt;performacne&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/programming" rel=tag mce_href="http://del.icio.us/popular/programming"&gt;programming&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/C%23" rel=tag mce_href="http://del.icio.us/popular/C%23"&gt;C#&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/multi-core" rel=tag mce_href="http://del.icio.us/popular/multi-core"&gt;multi-core&lt;/A&gt;,&lt;A href="http://del.icio.us/popular/multicore" rel=tag mce_href="http://del.icio.us/popular/multicore"&gt;multicore&lt;/A&gt;&lt;/DIV&gt;
&lt;P&gt;You can find the complete VS 2008 project in the attached ZIP file.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9859413" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/9859413.ashx" length="11021" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category></item><item><title>Beyond Hello World - Update 5, TreeMap Control Working, Perf Issues</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/03/24/beyond-hello-world-update-4-treemap-control-working-perf-issues.aspx</link><pubDate>Sat, 24 Mar 2007 21:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1943307</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1943307.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1943307</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1943307</wfw:comment><description>&lt;P&gt;&lt;A title="CLC Data Viewer project" href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx"&gt;CLCV&lt;/A&gt; V5 now has a fully working &lt;A title="TreeMap description" href="http://www.cs.umd.edu/hcil/treemap/" target=_blank mce_href="http://www.cs.umd.edu/hcil/treemap/"&gt;TreeMap&lt;/A&gt; control that zooms, supports mouse over events and looks pretty good.&amp;nbsp; The regions are&amp;nbsp;laid out with the &lt;A title="Squarified TreeMap algorithm" href="http://www.win.tue.nl/~vanwijk/stm.pdf" target=_blank mce_href="http://www.win.tue.nl/~vanwijk/stm.pdf"&gt;Squarified TreeMap algorithm&lt;/A&gt;.&amp;nbsp; Even better, the tree map itself scales to large numbers of nodes - easily 100's of thousands, and on &lt;A title="my lap top" href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx"&gt;my lap top&lt;/A&gt;, it will handle a couple of million nodes relatively well.&amp;nbsp;&amp;nbsp; But there are two major performance problems:&amp;nbsp; 1) WPF rendering seems to be &lt;EM&gt;very&lt;/EM&gt; expensive.&amp;nbsp; 2) Tree Map nodes are relatively expensive in terms of memory size.&amp;nbsp; This limits the number of nodes to a ~2 million.&amp;nbsp; You can find a link to the source code at the end of this post.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap16.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap16.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN: 0px 0px 0px 10px; BORDER-RIGHT-WIDTH: 0px" height=480 alt="Tree Map Sceen Shot" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap1_thumb6.png" width=345 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMap1_thumb6.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Note - all performance numbers (number of objects, times and profile data) are gathered from my &lt;A title="Acer Ferrari 5000" href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/ferrari-5000.aspx"&gt;new Acer Ferrari 5000 laptop&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;From a memory usage perspective the control performs acceptably for even a few hundred thousand nodes.&amp;nbsp; Tens of thousands of nodes are no problem.&amp;nbsp; But, it does begin to struggle with about a million, with two million being a empirical limit.&amp;nbsp; A future post on this WPF version of CLCV will focus on memory optimizations and usage in detail.&lt;/P&gt;
&lt;P&gt;For this post, I'll focus on WPF rendering performance.&amp;nbsp; In summary, the primary performance issue that limits the scaling of my treemap control isn't memory or CPU time to compute or render the layout - it is actual physical rendering of the rectangles and text by WPF itself.&amp;nbsp; WPF cannot keep up with more than about 750 rectangles and a small number of scaled text items.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;My treemap control is pretty well optimized (there is still some work to do) - but the computational performance of the control itself is not the limiting factor.&amp;nbsp; The most important aspect of my treemap implementation is that it is smart about how much work it does -limiting its computations and rendering to only the nods that are reasonably large.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;When learning about treemaps, I looked at some existing code and read all the web&amp;nbsp; material I could find.&amp;nbsp; It looks like most implementations are pretty basic - they compute the size and location of each rectangle for the entire tree.&amp;nbsp; I thought this was a bit odd.&amp;nbsp; It seemed to me that it would be more efficient to only process the part of the tree that would be visible - e.g. computing and rendering tiny or invisible rectangles didn't seem like a good design decision to me.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects2.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects2.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN: 0px 0px 0px 5px; BORDER-RIGHT-WIDTH: 0px" height=87 alt="Tiny Rectanges" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects_thumb2.png" width=122 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TinyRects_thumb2.png"&gt;&lt;/A&gt;My first implementation took the straight forward approach as well.&amp;nbsp;&amp;nbsp; As I suspected, for larger trees - even those with a only a few thousands nodes, computing and rendering tiny rectangles was a waste of computation and rendering time.&amp;nbsp; As you can see in the image to the right, rectangles that are smaller than some limit are too small to effectively&amp;nbsp;mouse over or to meaningfully discern their relative area with respect to their parent. &lt;/P&gt;
&lt;P&gt;So, I modified both the layout code and the rendering code to stop when the area of the rectangles became less than some threshold.&amp;nbsp; This worked very well both from a visual perspective and performance standpoint.&amp;nbsp; It also allows the data tree to become very large as it means that neither the layout and rendering costs grow with the overall tree size as the number of nodes surpasses the number of rectangles that the algorithm decides to actually render.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Experiment:&lt;/STRONG&gt; CLC V5 includes a unit test for the treemap control that allows you to control the size of the three and set the treemap parameters such as the &lt;STRONG&gt;Area Limit.&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT1.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT1.png"&gt;&lt;IMG style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=177 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT_thumb1.png" width=640 border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/TreeMapUT_thumb1.png"&gt;&lt;/A&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;The area limit is the minimum size of the rectangles that will be rendered.&amp;nbsp; Assuming there are enough nodes, the larger this number, the fewer rectangles will be visible.&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;From&amp;nbsp;empirical testing I determined that a value of 64 works pretty well.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For trees over a one or two thousand nodes, there are usually more nodes than can be displayed.&amp;nbsp;&amp;nbsp; In these scenarios, the scaling limitations are inherent to WPF itself, not the layout computations, or rendering in the treemap control.&lt;/P&gt;
&lt;P&gt;Its important to understand how the control works and when WPF actually does the visible rendering.&amp;nbsp; The treemap control has two main steps:&amp;nbsp;&amp;nbsp; the first is the actual layout computations of the tree, and the second is the rendering of the tree.&amp;nbsp;&amp;nbsp; Once the control is rendered, then WPF will take the rendering data generated in the control's OnRender function and actually turn that into DirectX commands that become visible on the screen.&amp;nbsp;&amp;nbsp; Its this third step that is the limiting factor.&lt;/P&gt;
&lt;P&gt;The layout computations are handled by a function called &lt;STRONG&gt;ComputeAllNodeBoundingRects&lt;/STRONG&gt;.&amp;nbsp; This &amp;nbsp;function starts at the root node and recursively&amp;nbsp;computes the size of each visible rectangle for the nodes in the tree.&amp;nbsp;&amp;nbsp;This function stops its recursion when it reaches nodes that have visible areas less than the &lt;STRONG&gt;Area Limit.&amp;nbsp; &lt;/STRONG&gt;You can experiment with area limit values&amp;nbsp;using the unit test (see above).&amp;nbsp; If you set the area limit to zero, then the layout computations will compute a rectangle for every node in the tree.&lt;/P&gt;
&lt;P&gt;Computing the bounding rectangles only needs to happen when the treemap control receives a new data tree (by setting the TreeMapData property), or when the render size changes (handled by the OnRenderSizeChanged event).&lt;/P&gt;
&lt;P&gt;When WPF determines that a control needs to be rendered, it calls the controls OnRender method.&amp;nbsp; This control's OnRender method recursively paints each of the rectangles computed in ComputeAllNodeBoundingRects.&amp;nbsp;&amp;nbsp; It also renders the text for the root nodes and first level nodes. &lt;/P&gt;
&lt;P&gt;Both of these functions are relatively fast - here are some statistics for the initial random tree.&amp;nbsp; LQ means 'lower quartile',&amp;nbsp;UQ means 'upper quartile', IQ range is the inter quartile range divided by the median value.&amp;nbsp;&amp;nbsp; Range is the total range (max-min) divided by the median.&amp;nbsp; Times are in milliseconds.&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=2 width=524 border=0 unselectable="on"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=78&gt;&amp;nbsp;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=46&gt;&lt;STRONG&gt;Count&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Min&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;LQ&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Median&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;Mean&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=33&gt;&lt;STRONG&gt;UQ&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=40&gt;&lt;STRONG&gt;Max&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;&lt;STRONG&gt;IQ Range %&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;&lt;STRONG&gt;Range %&lt;/STRONG&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=75&gt;&lt;STRONG&gt;Compute&lt;/STRONG&gt;&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=48&gt;100&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;2.6&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;2.8&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.0&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.4&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;3.4&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=41&gt;7.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;18.4%&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;171.7%&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD class="" vAlign=top align=right width=76&gt;&lt;STRONG&gt;Render&lt;/STRONG&gt; &lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=50&gt;100&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;5.8&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;6.2&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;6.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;7.3&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=34&gt;7.7&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=41&gt;19.6&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=104&gt;21.8%&lt;/TD&gt;
&lt;TD class="" vAlign=top align=right width=82&gt;204.9%&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;These times are for computing and rendering from&amp;nbsp;1,316 to 1,539 visible nodes.&amp;nbsp;&amp;nbsp;&amp;nbsp;As you can see from the times, neither compute nor rendering times in the control itself should inhibit the control from rendering smoothly.&amp;nbsp; This is especially true when the control is rendering due to events other than size changes. &lt;/P&gt;
&lt;P&gt;But, even with the times above, the control still struggles to render - you can see this by just rolling the mouse over the control and watching the lagging mouse-over node changes, or by resizing the control.&amp;nbsp; In both cases, if the control is painting more than 700 rectangles or so, then it can't keep up.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization%5B1%5D.png" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization%5B1%5D.png"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; MARGIN: 0px 0px 0px 5px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=124 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization_thumb%5B1%5D.png" width=240 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4TreeMapControlWor_8C13/CpuUtilization_thumb%5B1%5D.png"&gt;&lt;/A&gt;While relatively anecdotal, the CPU utilization for the control also seems on the high side.&amp;nbsp; Just continually moving the mouse over the control uses considerable CPU, 70 to 80%.&amp;nbsp; This is high,&amp;nbsp;especially considering that my lap top has a dual core AMD Turion processor with has a &lt;A title="Windows Experience Index" href="http://windowsvistablog.com/blogs/windowsvista/pages/458117.aspx" target=_blank mce_href="http://windowsvistablog.com/blogs/windowsvista/pages/458117.aspx"&gt;WinEI&lt;/A&gt; rating of 4.8.&lt;/P&gt;
&lt;P&gt;While there does seem to be some material performance and scaling issues with WPF, there is a lot to like about the programming model.&amp;nbsp;&amp;nbsp; I'll talk about this more in subsequent posts.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;STRONG&gt;Source Code for this post:&amp;nbsp; &lt;/STRONG&gt;CLCV-BLOG-5.ZIP contains the source code to this post.&amp;nbsp;&amp;nbsp; I didn't include the data files in this zip file as they haven't changed - you can simply use the ones from &lt;A href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx" mce_href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx"&gt;CLCV-BLOG-3.ZIP&lt;/A&gt;.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1943307" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1943307.ashx" length="81780" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx">Beyond Hello World</category></item><item><title>Beyond Hello World - Update 4, File loading 27 times faster!</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/01/30/beyond-hello-world-update-4-file-loading-27-times-faster.aspx</link><pubDate>Wed, 31 Jan 2007 02:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1559624</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1559624.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1559624</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1559624</wfw:comment><description>&lt;p&gt;&lt;a title="Overview" href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx" target="_blank"&gt;CLCV&lt;/a&gt; V4 now loads files about 27 times faster than &lt;a title="CLCV Version 3" href="http://blogs.msdn.com/pigscanfly/archive/2007/01/22/beyond-hello-world-update-3-control-templates-multithreading-and-more-with-source.aspx" target="_blank"&gt;V3&lt;/a&gt;&amp;nbsp;when running on &lt;a href="http://blogs.msdn.com/pigscanfly/pages/ferrari-4000.aspx"&gt;my laptop&lt;/a&gt;.&amp;nbsp;&amp;nbsp; The tree view is also about 5 times faster.&amp;nbsp; This comes from changing my initial naive implementation to a smarter one where I minimize the inter-thread communication and handle the tree view much more efficiently.&amp;nbsp; More information about the source code is at the bottom of this post.&amp;nbsp; Here is what I learned in working on V4.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Updating WPF UI elements can be expensive for large numbers of items.&amp;nbsp; An effective&amp;nbsp;and simple strategy is to&amp;nbsp;only load data into WPF UI elements that the user actually needs to see - don't use WPF objects as the store for large numbers of objects.&amp;nbsp;&amp;nbsp; &lt;br&gt; &lt;li&gt;Updating pixels on the screen is expensive - even with relatively high performance hardware.&amp;nbsp; Changing pixels (e.g. updating UI controls) at a rate faster than the monitor refresh rate is a waste of system resources, CPU time, GPU time, and memory bandwidth.&amp;nbsp; UI updates that are related to (or driven from) high throughput tasks should be paced to&amp;nbsp;no more than the monitor refresh rate. &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;V3 was the first&amp;nbsp;functional version of CLCV and while it worked, it loaded files very slowly - talking 90 seconds or so (on my laptop) to load the largest data file (about 8.75MB in size).&amp;nbsp; Given that the ultimate goal is to handle CSV files that hold data for the entire Windows Vista source code tree, I really needed to improve CLCV's performance.&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00121%5B5%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="331" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00121_thumb%5B2%5D.png" width="499" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The cause of the performance problem was easy to find using the Visual Studio 2005 profiler.&amp;nbsp; I simply enabled instrumented profiling and the offending code was obvious.&lt;/p&gt; &lt;p&gt;The most time consuming operation in V3 wasn't the actual file read time, it was the overhead of building the tree of tree view items.&amp;nbsp; In V3, the file reading thread sent a message to the UI thread for every new file and directory from the CSV file.&amp;nbsp; The UI thread then added that information to the&amp;nbsp;tree of tree view control items as the file was read.&amp;nbsp; This was very time consuming and took much longer than actualy reading the file. &lt;/p&gt; &lt;p&gt;It turns out that building a tree of tree view items is simply expensive.&amp;nbsp; The most expensive part being setting the string that is displayed as the item's header.&amp;nbsp; This&amp;nbsp;is closely followed by actually making a new item the child of another (ItemCollection.Add).&amp;nbsp; I don't yet know why this is expensive, only that it is.&amp;nbsp; It may be because I'm building the tree bottom up instead of top down - &lt;a title="Kiran Kumar's blog" href="http://blogs.msdn.com/kiranku/" target="_blank"&gt;Kiran Kumar&lt;/a&gt;&amp;nbsp;discusses this as a potential issue &lt;a title="WPF performance white paper" href="http://blogs.msdn.com/kiranku/attachment/904197.ashx" target="_blank"&gt;here&lt;/a&gt;.&amp;nbsp; I need to chat with my friend &lt;a title="Time Cahill's blog on WPF performance" href="http://blogs.msdn.com/timothyc" target="_blank"&gt;Tim Cahill&lt;/a&gt; the WPF performance guy about this a bit more.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;For V4, I took a different approach: I re-factored the code so the&amp;nbsp;file loading thread now does all the work of constructing a tree of objects that represent the original&amp;nbsp;directory structure and its files.&amp;nbsp;&amp;nbsp;I also moved the logic that updates the progress bar from the UI thread to the file loader thread - only sending progress messages to the UI thread every 33 milliseconds (this is configurable).&amp;nbsp;&lt;/p&gt; &lt;p&gt;The results were dramatically better.&amp;nbsp; The file loader thread could read the file and re-construct the directory tree much faster than the previous version.&amp;nbsp; On my laptop, the 8.75MB file could be loaded in about 1.47 seconds&amp;nbsp;- not bad at all.&amp;nbsp; In this version, the file loader thread sends a message to the UI thread to update the progress bar no more frequently than every 33 milliseconds (about 30 times per second).&amp;nbsp;&amp;nbsp;This is more than often enough so that the progress bar is visibily smooth, but not so much&amp;nbsp;that&amp;nbsp;updating the progress bar takes too long.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Experiment: &lt;/strong&gt;Updating the progress bar is expensive - way to expensive to do this for every line read from the file.&amp;nbsp;&lt;strong&gt; &lt;/strong&gt;You can see how expensive this can be by using CLCV V4 and&amp;nbsp;setting the "Progress Update Interval" in the options dialog box to 0.&amp;nbsp;&amp;nbsp; When this is zero, the file reading thread will send a message to the UI thread for every record read from the the CSV file.&amp;nbsp;&amp;nbsp; The messages get queued up in the UI threads dispatcher object and processed as fast as the UI can handle them.&amp;nbsp;&amp;nbsp; Processing all these messages and updating the progress bar takes a much longer time than processing the entire file!&amp;nbsp; The lesson here is that the overall process of updating the UI (chaning pixels on the screen) is simply expensive.&amp;nbsp; There is really no need to update the UI faster than the monitor refresh rate.&amp;nbsp; Often about 1/2 to even 1/3 of the monitor refresh rate is just fine.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Note that for most things, a UI update rate of 30 or so updates per second will present a smooth animaition to the user.&amp;nbsp;&amp;nbsp; If needed, updating the UI faster -- at or close to the monitor refresh rate -- will work well.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Next, I needed a strategy for minimizing the costs of building the tree of tree view items that display the directory tree and files. Given that the file reader thread builds a tree structure, the solution was simple:&amp;nbsp; CLCV V4 only populates the tree view control when it needs to, and&amp;nbsp;only populates the items the user needs to see.&amp;nbsp; After the file is loaded, the UI code updates the tree view with the top level elements.&amp;nbsp; When the user expands an element, the UI thread then populates the data for that item's children.&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;In this way, CLCV only pays the costs for populating elements the user needs to see; only tree view items that will actually be displayed are created and added to the tree view item tree.&amp;nbsp; This also amortizes the costs of the items displayed over the time the user actualy minipulates the control.&amp;nbsp; So even if the user browses the entire three, he never experiences a sluggish tree view control.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Experiment: &lt;/strong&gt;This works quite well, if you use CLCV version 3 to load the large test file (test-l.clc.csv) the first click on the bottom entry ("GSFD") will take a noticeably, and annoyingly, long time to expand ( about 2.5 seconds on my laptop).&amp;nbsp;&amp;nbsp; With V4, this happens quickly: it takes about 150ms to populate 922 child items (~6,000 items per second, or ~166us).&amp;nbsp; It looks like it takes about anothe r300 milliseconds to draw the new items: its hard to measure this because WPF doesn't have a begin and ending events for item expansion (I just used a stop watch).&lt;/p&gt;&lt;/blockquote&gt; &lt;p style="margin: 0in 0in 0in 0.375in"&gt;&lt;a href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00131%5B4%5D.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="333" src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate4Fileloading27time_93BD/clip_image00131_thumb%5B1%5D.png" width="609" border="0"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;With V4, the profiler shows a very different picture: The bulk of the CPU time during file loading is spent actually parsing the text data from the file, primarily converting text fields to decimal values using UInt32.TryParse().&lt;/p&gt; &lt;p&gt;This is as expected.&amp;nbsp; It probably isn't worth optimizing the conversion operations&amp;nbsp;by writing a hand crafted text to Uint32 conversion routine as such a routine would need to handle localization and othe rissues.&amp;nbsp; I expect it would only result modest performance improvements.&amp;nbsp; The primary file loading bottleneck in V4 isn't CPU time, but I/O efficiency.&lt;/p&gt; &lt;p&gt;Loading a 8.75MB file in 1.47 seconds is pretty good - its about&amp;nbsp;6 MB/s; and its plenty fast enough for my intended scenario.&amp;nbsp;&amp;nbsp; But, it is still slow compared to other applications.&amp;nbsp; I've developed other tools (such as CLC itself) that are completly I/O bound and use only one thread for the entire application.&amp;nbsp; These tools easily drive the disk at its maximum sequential read rate of about 35 MB/s while handling much more complex string opeations than merely parsing some CSV data.&amp;nbsp; For example, CLC is an order of magnitude faster than CLCV.&amp;nbsp; The reason is the stream reader class&amp;nbsp;- it doesn't do asynchronous or un-buffered I/O and its paying the cost of transcoding ANSI or UTF8 text into UTF16 for storing in .NET string objects.&amp;nbsp;&amp;nbsp;&lt;/p&gt; &lt;p&gt;In contrast, my natively implemented tools read files fully asynchronously in un-buffered mode.&amp;nbsp; This makes I/O operations happen in paralell with data processing - not sequentially.&amp;nbsp; They also parse the text data directly from the buffers populated by the operating system file read operation - no data copies are needed.&amp;nbsp; Next,&amp;nbsp;they handle ANSI and UNICODE directly - they don't transcode all input text to UTF-16.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt; &lt;p&gt;Now this isn't to say that the StreamBuffer class is slow - it isn't.&amp;nbsp; Using off the shelf I/O libraries in native C++ results in comparable performance to the .NET StreamBuffer class.&amp;nbsp; The difference comes from using hand crafted I/O routines specificaly designed to for sequntial text line reading and maximizing parallism between disk I/O and computation.&amp;nbsp; &lt;/p&gt; &lt;p&gt;One of my future tasks is writing a COM wrapper for my hand crafted C++ I/O libraries so they can be used efficiently from .NET languages.&amp;nbsp; I expect this will allow CLCV to come very close to the file read performance of my native tools. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Source Code for this post:&amp;nbsp; &lt;/strong&gt;CLCV-BLOG-4.ZIP contains the source code to this post.&amp;nbsp;&amp;nbsp; I didn't include the data files in this zip file as they haven't changed - you can simpy use the ones from &lt;a title="V3 Zip File" href="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx" target="_blank"&gt;CLCV-BLOG-3.ZIP&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p style="margin: 0in"&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1559624" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1559624.ashx" length="47521" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category></item><item><title>Beyond Hello World - Update 3, Control Templates, Multithreading, and more... (with source)</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/01/22/beyond-hello-world-update-3-control-templates-multithreading-and-more-with-source.aspx</link><pubDate>Mon, 22 Jan 2007 04:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1505442</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1505442.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1505442</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1505442</wfw:comment><description>&lt;P&gt;I've&amp;nbsp;learned a lot&amp;nbsp;in working on&amp;nbsp;&lt;A title="Info on my first real WPF application" href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/pages/clc-and-it-s-data-viewer-clcv.aspx"&gt;my first real WPF application&lt;/A&gt;&amp;nbsp;such as implimenting multi-threaded file reading, how to use the dispatcher object, how to use &lt;A title="Control Template examples" href="http://msdn2.microsoft.com/en-us/library/aa970773.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa970773.aspx"&gt;control templates&lt;/A&gt; to customize controls, the basics of application configuration, using abstract C# classes, and using &lt;A title="Aononymous Methods" href="http://msdn2.microsoft.com/en-us/library/0yw3tz5k.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/0yw3tz5k.aspx"&gt;anonymous methods&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;I've posted the source code that goes along with this post.&amp;nbsp; It is in the file &lt;STRONG&gt;CLCV-Blog-3.ZIP&lt;/STRONG&gt; at the end of this post.&amp;nbsp; This version of CLCV has some new features&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;It has an option dialog box for setting the user's preferences.&amp;nbsp; This mechanism uses the application properties wizard in Visual Studio - this was surprisingly easy to do, but it does have one problem; I can't control where the data is saved! (yet).&lt;/LI&gt;
&lt;LI&gt;File I/O is multi-threaded.&amp;nbsp; One thread reads the lines from the CSV input file and sends the resulting data to the UI thread using the UI's &lt;A title="Dispatcher Class" href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx"&gt;Dispatcher&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;File reading can be quickly canceled - an important attribute for a program that is designed to load large files. &lt;/LI&gt;
&lt;LI&gt;CLCV displays an &lt;EM&gt;accurate &lt;/EM&gt;progress bar as it loads the file.&amp;nbsp;&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;The recently used file list now works correctly&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;It discards files that no longer exist when CLCV starts&lt;/LI&gt;
&lt;LI&gt;It keeps the list sorted in order of use (most recent at the top).&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;There are &lt;EM&gt;many&lt;/EM&gt; new concepts for a native C++ developer to learn when ramping up on WPF and C#.&amp;nbsp; One of the most important is how to customize the look and feel of your applications - this is&amp;nbsp;a &lt;A title="Raison D’être" href="http://en.wikipedia.org/wiki/Raison_d%27%C3%AAtre" target=_blank mce_href="http://en.wikipedia.org/wiki/Raison_d%27%C3%AAtre"&gt;Raison D’être&lt;/A&gt; for WPF.&amp;nbsp; In my earlier versions of CLCV, I couldn't figure out how to customize the look and feel of buttons so I rolled my own using a rectangle and some animations.&amp;nbsp; It looked ok, but this was completely the wrong way to go about it.&lt;/P&gt;
&lt;P&gt;One of my friends (Joe Laughlin) pointed me in the right direction: &lt;A title="Customizing WPF Controls" href="http://msdn2.microsoft.com/en-us/library/ms752043.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/ms752043.aspx"&gt;Customizing controls&lt;/A&gt; is easily done using &lt;A title="Control Template Examples" href="http://msdn2.microsoft.com/en-us/library/aa970773.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/aa970773.aspx"&gt;Control Templates&lt;/A&gt; which are designed to do exactly what I needed: completely controling the look and feel of &lt;U&gt;any&lt;/U&gt; WPF control while maintaining their semantics.&amp;nbsp; Even better, with WPF resources, this can be asily done for an entire application.&amp;nbsp; Control templates made it stright foreward for me to set the look and feel of buttons in my application to a&amp;nbsp;blue colored&amp;nbsp;theme.&amp;nbsp; So far,&amp;nbsp;I've just scratched the surface of control templates, but you can see what I did by looking in &lt;STRONG&gt;resources\button.xaml.&lt;/STRONG&gt;&amp;nbsp; It is&amp;nbsp;tied into the application in &lt;STRONG&gt;App.xaml&lt;/STRONG&gt; like this:&lt;/P&gt;&lt;PRE class=csharpcode&gt;    &amp;lt;Application.Resources&amp;gt;
        &amp;lt;ResourceDictionary&amp;gt;
            &amp;lt;ResourceDictionary.MergedDictionaries&amp;gt;
                &amp;lt;ResourceDictionary Source=&lt;SPAN class=str&gt;"Resources\Button.xaml"&lt;/SPAN&gt; /&amp;gt;
            &amp;lt;/ResourceDictionary.MergedDictionaries&amp;gt;
        &amp;lt;/ResourceDictionary&amp;gt;
    &amp;lt;/Application.Resources&amp;gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/STYLE&gt;

&lt;P&gt;The XAML above applies my customized Button control template to every button in the application without&amp;nbsp;touching the XAML for the other windows or&amp;nbsp;pages.&amp;nbsp;This is very cool. More than cool, its a great example of how WPF separates design (look and feel) from an application's &lt;A title="Defintion of Semantics" href="http://en.wikipedia.org/wiki/Semantics" target=_blank mce_href="http://en.wikipedia.org/wiki/Semantics"&gt;semantics&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate3Contro.withsource_DB12/OptionsDialog%5B16%5D.jpg" atomicselection="true" mce_href="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate3Contro.withsource_DB12/OptionsDialog%5B16%5D.jpg"&gt;&lt;IMG style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; MARGIN: 0px 0px 0px 10px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=299 src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate3Contro.withsource_DB12/OptionsDialog_thumb%5B10%5D.jpg" width=306 align=right border=0 mce_src="http://blogs.msdn.com/blogfiles/pigscanfly/WindowsLiveWriter/BeyondHelloWorldUpdate3Contro.withsource_DB12/OptionsDialog_thumb%5B10%5D.jpg"&gt;&lt;/A&gt;An important feature of CLCV V3 is its options dialog box.&amp;nbsp; This makes it easy to tweak and tune key&amp;nbsp;parameters without recompiling.&amp;nbsp; Here is some&amp;nbsp;info on&amp;nbsp;the options:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Show Console: when checked, CLCV will display its debug/diagnostic console.&lt;/LI&gt;
&lt;LI&gt;Synchronous Line Reads: this forces the file reader thread to post messages to the UI thread synchronously using &lt;A title="Invoke Method" href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx"&gt;Invoke()&lt;/A&gt; instead of &lt;A title="Begin Invoke Method" href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke.aspx"&gt;BeginInvoke()&lt;/A&gt;. ( using Invoke()this is slow)&lt;/LI&gt;
&lt;LI&gt;Animate Directory Loading: when checked, this forces CLCV to visibly populate the tree view control as items are read (this is slow).&lt;/LI&gt;
&lt;LI&gt;Maximum Outstanding Messages: this is the maximum number of outstanding messages the file reader thread will have with the UI thread. &lt;/LI&gt;
&lt;LI&gt;Message priority: this is the &lt;A title="Dispatcher Priority" href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx"&gt;DispatcherPriority&lt;/A&gt;&amp;nbsp; used by the reader thread send messages to the UI thread (in the calls to Invoke() or BeginInvoke().&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;While V3 of CLCV is still naively implemented in many regards (this is my first WPF app and I only started with C# and WPF in &lt;A title="Starting WPF and C#" href="http://blogs.msdn.com/pigscanfly/archive/2006/12/27/wpf-styles.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/archive/2006/12/27/wpf-styles.aspx"&gt;late December '06&lt;/A&gt;).&amp;nbsp; But, I knew from the get go that I'd have to handle file reading in a thread separate from the UI thread to avoid UI hangs and sluggishness during file loading.&lt;/P&gt;
&lt;P&gt;Of course, it is&amp;nbsp;possible for single threaded applications to efficiently read files and keep their UI responsive - I have a native C++ class that provides I/O support for this.&amp;nbsp; My native class is extremely efficient and can easily drive the disk at its maximum sequential read rate with one thread. But, this is more complex in .NET 3.0.&amp;nbsp; While .NET does provide the fundamental support for asynchronous I/O, I'd essentially have to re-implement my Native C++ classes in C# and I'm not ready for that yet.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;This approach would also be just as messy in WPF&amp;nbsp;as it would be in native code: mixing I/O&amp;nbsp;and procssing UI events in one thread requires&amp;nbsp;a state machine approach to handle issuing asynchronous reads,&amp;nbsp;processing UI messages, and handling completed read events.&amp;nbsp; This is prone to complexity and can be difficult to debug and maintain. &lt;/P&gt;
&lt;P&gt;Fortunately, it&amp;nbsp;is&amp;nbsp;very easy to create a file reading thread in .NET and for that thread to send its data to the UI thread asynchronously.&amp;nbsp; It takes surprisingly little code to do this:&lt;/P&gt;
&lt;DIV class=csharpcode&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   1:  &lt;/SPAN&gt;        &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; FileLoader( DataViewWindowClass dvw )&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   2:  &lt;/SPAN&gt;        {&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   3:  &lt;/SPAN&gt;            MyDataViewWindow = dvw;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   4:  &lt;/SPAN&gt;&amp;nbsp;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   5:  &lt;/SPAN&gt;            UseSyncronousLineReads      = TheApp.UserProperties.SyncronousLineReadsFlag;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   6:  &lt;/SPAN&gt;&amp;nbsp;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   7:  &lt;/SPAN&gt;            StartFileLoadHandler       += MyDataViewWindow.StartFileLoad;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   8:  &lt;/SPAN&gt;            NewFileHandler             += MyDataViewWindow.AddNewFileHandler;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;   9:  &lt;/SPAN&gt;            NewDirHandler              += MyDataViewWindow.AddNewDirHandler;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  10:  &lt;/SPAN&gt;            NewDirTreeHandler          += MyDataViewWindow.AddNewDirTreeHandler;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  11:  &lt;/SPAN&gt;            FileCompletedSignalHandler += MyDataViewWindow.FileCompletedSignal;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  12:  &lt;/SPAN&gt;&amp;nbsp;&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  13:  &lt;/SPAN&gt;            FileLoaderThreadEntryPoint  = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; ThreadStart( LoaderThread );&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  14:  &lt;/SPAN&gt;            MyThread                    = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Thread( FileLoaderThreadEntryPoint );&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  15:  &lt;/SPAN&gt;            WaterMarkSemaphore          = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; Semaphore( TheApp.UserProperties.MaxOutstandingMessageCount, &lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  16:  &lt;/SPAN&gt;                                                         TheApp.UserProperties.MaxOutstandingMessageCount );&lt;/PRE&gt;&lt;PRE&gt;&lt;SPAN class=lnum&gt;  17:  &lt;/SPAN&gt;        }&lt;/PRE&gt;&lt;/DIV&gt;
&lt;STYLE type=text/css&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/STYLE&gt;

&lt;P&gt;The code above is from &lt;STRONG&gt;DataView.Xaml.cs&lt;/STRONG&gt;.&amp;nbsp; It creates the FileLoader object which owns the file reading thread.&amp;nbsp; The reading thread uses five delegates to communicate with the UI thread: &lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;One to signal that the file loading operation has actually started.&amp;nbsp; This message is used to send the file size to the UI thread so it can setup the progress bar.&lt;/LI&gt;
&lt;LI&gt;One message each for for files, directories, and directory trees.&amp;nbsp;&amp;nbsp; Each of these messages also includes the number of bytes read from the file so far.&amp;nbsp; This allows the UI thread to keep the progress bar up to date.&lt;/LI&gt;
&lt;LI&gt;And finally, one to signal that the file read is completed. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The reading thread does all the work to read the file, which is in comma separated value (CSV) format.&amp;nbsp; The CSV file contains all the data necessary for CLCV to reconstruct the directory tree scanned by CLC.&amp;nbsp; (note, in the TestData directroy from ZIP file, I've included three CSV files, one small, one medium sized, and one large - this is actual data from some of my source code trees).&lt;/P&gt;
&lt;P&gt;The reader thread handles the following work&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;file reads using a StreamReader object&lt;/LI&gt;
&lt;LI&gt;detecting header lines and blank lines&lt;/LI&gt;
&lt;LI&gt;splitting each line into the comma separated fields&lt;/LI&gt;
&lt;LI&gt;parsing and converting the text data to binary data and putting that data in objects&lt;/LI&gt;
&lt;LI&gt;sending those objects to the UI thread&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;All in all, this works quite well for a first attempt: the UI stays alive (doesn't hang), the file read operation can be quickly canceled, and its all done with straight forward code. &lt;/P&gt;
&lt;P&gt;Note that getting the dispatch priority correct is very important.&amp;nbsp; On a single CPU system (like my laptop), using too low a priority simply causes the entire process to drag out.&amp;nbsp; Using too high a priority causes the I/O thread to starve the UI thread.&amp;nbsp; For example, if you set the dispatch priority to "input", then the UI thread may need to work through large numbers of input messages before it processes input events, such as a cancel request.&amp;nbsp;&amp;nbsp; Setting the dispatch priroity above "input" (to "loaded" or "render") will keep input events from being processed.&lt;/P&gt;
&lt;P&gt;Going higher, to "render" will interfere with the actual rendering of the UI causing the progress bar to be jerky.&amp;nbsp; Going higher than "render"&amp;nbsp; to "databind", "normal", or "send" completly stops UI rendering and blocks all input thus hanging the UI; this is specific problem&amp;nbsp;that multi-threaded I/O is intended to handle.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The "Background" dispatch priority seems to work acceptably well.&amp;nbsp; Using this priority, the UI remains responsive while consuming input events fromt the reader thread relativly smoothly.&lt;BR&gt;&lt;BR&gt;Note that using dispatcher priorities is orthogonal to setting thread priorities - the dispatcher priority is simply the priority at which the dispatcher removes input events (delegates) from its input queues. &lt;/P&gt;
&lt;P&gt;But, there are some performance issues in this initial naive implementation:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;The progress bar doesn't terminate nicely - it gets updated to 100% complete in the UI file completion routine (see the function FileCompletedSignal() ), but WPF spends a &lt;U&gt;lot&lt;/U&gt; of time in this function before it re-renders the UI.&amp;nbsp; I need to figure this out.&lt;BR&gt;&lt;/LI&gt;
&lt;LI&gt;The biggest problem is the time it takes to actually build set of tree view items that are used to populate the list of directories and files.&amp;nbsp;&amp;nbsp; This takes 10 to 20 times &lt;U&gt;more&lt;/U&gt; than the actual file I/O, which is very surprising given that in native code, I have tools that do significantly more text processing while still remaining I/O bound - all in one thread.&lt;BR&gt;&lt;/LI&gt;For small trees (just a few hundred items) this is fast enough not to be annoying (try loading the small and medium size test files).&amp;nbsp; However, for the 83,000+ elements in the largest file, processing all the data into TreeView items is excruciatingly slow.&lt;BR&gt;&lt;BR&gt;
&lt;LI&gt;The performance of the tree view control itself also bogs down with the largest file.&amp;nbsp;&amp;nbsp; Its noticeably sluggish when the selection changes. &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;That being said, my first implimention is certainly naive - I simply build a set of tree view items that mirror the entire file and directory structure.&amp;nbsp; It doesn't look like too much trouble be a lot smarter about this - populating the tree view as needed from another data structure.&amp;nbsp; I'm going to try this next.&lt;/P&gt;
&lt;P&gt;In upcoming posts, I'll explore better ways to handle the TreeView control (only populating it as necessary), do some profiling to see if I can speed up data processing, and add some more advanced control templates, and explain why its important to throttle the number of messages from the file reading thread (a producer) to the UI thread (the consumer). &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1505442" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1505442.ashx" length="2450462" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx">Beyond Hello World</category></item><item><title>Beyond Hello World - An Update On My First WPF Application (with source)</title><link>http://blogs.msdn.com/pigscanfly/archive/2007/01/03/beyond-hello-world-an-update-on-my-first-wpf-application-with-source.aspx</link><pubDate>Thu, 04 Jan 2007 02:28:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1407434</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1407434.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1407434</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1407434</wfw:comment><description>&lt;P&gt;I've been working on my first useful WPF application and I've learned several things since my &lt;A title="Update on my first WPF application" href="http://blogs.msdn.com/pigscanfly/archive/2006/12/30/beyond-hello-world-my-first-wpf-application.aspx" target=_blank mce_href="http://blogs.msdn.com/pigscanfly/archive/2006/12/30/beyond-hello-world-my-first-wpf-application.aspx"&gt;last post&lt;/A&gt;&amp;nbsp;and answered a few questions.&amp;nbsp; I've included a ZIP file with my updated source (you can find it at the bottom of the post, it includes full Visual Studio 2005 project) Here is what I've leaned:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;How to create wrapper functions for native Win32 interfaces.&lt;/LI&gt;
&lt;LI&gt;How to create a console window and direct the output to the Trace and Debug classes to the console window.&lt;/LI&gt;
&lt;LI&gt;How to create an animated button using a rectangle, styles, and a&amp;nbsp;storyboard - all in XAML.&lt;/LI&gt;
&lt;LI&gt;How to close a WPF Window object.&lt;/LI&gt;&lt;/OL&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;(1)&lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt; Of course it is possible to write a WPF or managed application without calling Win32 APIs.&amp;nbsp; But that can sometimes be limiting as there is&amp;nbsp;functionality provided by the Win32 APIs that are not available via .NET classes.&amp;nbsp; The WIn32 console classes are a good example: .NET provides the &lt;A title="Console Class" href="http://msdn2.microsoft.com/en-us/library/system.console.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.console.aspx"&gt;Console class&lt;/A&gt;, but no methods for actually creating or manipulating the console window itself.&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;I knew from talking to others that calling native API's should be easy and I found a few examples of this using marshaling.&amp;nbsp;&amp;nbsp; However, the examples didn't work for some of the APIs I needed.&amp;nbsp;&amp;nbsp; So, I emailed the internal .NET development alias with a couple of questions.&amp;nbsp; It turns out that calling native Win32 APIs is really, really easy - much easier than some of the examples on the web.&amp;nbsp; You can see how to do this in the &lt;STRONG&gt;Win32API.CS &lt;/STRONG&gt;file.&amp;nbsp; &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Here are a few things to note in this file:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;There are no explicit marshaling statements.&amp;nbsp;&amp;nbsp;When declared correctly, the C# compiler generate the interfaces correctly.&amp;nbsp;&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;Note that the output parameters that need a pointer to a structure are simply declared using the 'ref' statement.&amp;nbsp;&amp;nbsp; A .NET class&amp;nbsp;would&amp;nbsp;have worked here as well, but value objects (structs) seemed more appropriate.&lt;/LI&gt;
&lt;LI&gt;You should use &lt;STRONG&gt;IntPtr&lt;/STRONG&gt; as the type for handle - these are compatible with the safe handle classes.&lt;/LI&gt;
&lt;LI&gt;Note the use of types like &lt;STRONG&gt;UInt32&lt;/STRONG&gt; and &lt;STRONG&gt;UInt16&lt;/STRONG&gt; which mirror the standard Win32 data types.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#0000ff&gt;(2)&lt;/FONT&gt;&lt;/STRONG&gt;&amp;nbsp;I learned how to use the trace and debug classes with a console window from the application itself.&amp;nbsp; CLCV now creates its own console window and uses the &lt;A title="Console Trace Listener Class" href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.consoletracelistener.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.consoletracelistener.aspx"&gt;ConsoleTraceListener class&lt;/A&gt; to direct all the output to the &lt;A title="Trace Class" href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.trace.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.trace.aspx"&gt;Trace&lt;/A&gt; and &lt;A title="Debug Class" href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.trace.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.diagnostics.trace.aspx"&gt;Debug&lt;/A&gt; classes to the console window.&amp;nbsp; This was a bit tricky as I needed to interface directly with some low level Win32 APIs.&amp;nbsp;&amp;nbsp; To do this, I created two wrapper classes called K32 and U32.&amp;nbsp; These classes provide the data structures and interfaces necessary to call into the Kernel32 and User32 DLLs respectively. &lt;/P&gt;
&lt;P&gt;With these interfaces, its straight forward to create a console, open up the CONOUT$ handle to activate STDOUT, then set the size of the console window to 50 lines and 132 columns (the default is a bit small).&amp;nbsp; This is really handy - it allows me to see the trace and debug output without using any other applications. &lt;/P&gt;
&lt;P&gt;I'll update CLCV to make this console window optional in the future using a configuration dialog and possibly a hidden control.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;STRONG&gt;(3) &lt;/STRONG&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt;The WPF Button object is nice, but it controls its own behavior when it gets the&amp;nbsp;focus - there is no way to control this.&amp;nbsp; So, I decided I wanted a spiffier close button on my main window.&amp;nbsp;&amp;nbsp; After about three&amp;nbsp;hours of reading documentation and experimenting, I developed used a &lt;A title="Rectangle Class" href="http://msdn2.microsoft.com/en-us/library/system.windows.shapes.rectangle.aspx" target=_blank mce_href="http://msdn2.microsoft.com/en-us/library/system.windows.shapes.rectangle.aspx"&gt;Rectangle object&lt;/A&gt; to build a nice close button with a mouse over animation.&amp;nbsp;This was a little tricky because the Rectangle object doesn't support the IsMouse over property, it only supports MouseEnter and MouseLeve.&amp;nbsp; This mean I needed to animate both events.&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000000&gt;The outcome was pretty nice even though I'm a pretty poor UI designer (check it out!) &lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT color=#0000ff&gt;(4)&lt;/FONT&gt;&lt;/STRONG&gt; Doh!&amp;nbsp; Sometimes things are so simple.&amp;nbsp; The code in the previous post simply used the red X button in the window frame to close the app because I couldn't find the event or message to close the window.&amp;nbsp;&amp;nbsp; I was trying too hard!&amp;nbsp;&amp;nbsp; Closing a WPF window object is trivially easy - just call its &lt;STRONG&gt;Close() &lt;/STRONG&gt;method. &lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I continue to be surprised with how easy many things are with WPF and .NET.&amp;nbsp; For example, the animated close button would require large amounts of relatively complex code in C++.&amp;nbsp; With WPF, the animation itself took zero C# code and 33 lines of simple XAML code.&amp;nbsp; With even a basic understanding of XAML (which is what I currently have), the code for the button is straight forward and easy to understand.&amp;nbsp; I believe that anyone who is proficient in HTML could understand what is happening without know XMAL.&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I'm really starting to see how XAML is a great bridge between designers and developers - while it can be complex, its straight forward enough to be understood by people who are not developers.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Of course, all this simplicity comes at a price - the XAML and .NET run times are not free - they can have significantly more computational overhead and memory usage than native code.&amp;nbsp; That being said, it seems like a reasonable price to pay for many types of applications and (like many technologies) they will get more efficient over time.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;U&gt;Notes on the source code&lt;/U&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;This update includeI some very nicely implemented class from Sven Groot (&lt;A href="http://www.ookii.org/" mce_href="http://www.ookii.org/"&gt;Ookii.org&lt;/A&gt;)&amp;nbsp;that make it easy to use the Vista style common file dialogs for .NET 2.0 (version 1.2).&amp;nbsp; You can get the full package &lt;A href="http://www.ookii.org/software/" mce_href="http://www.ookii.org/software/"&gt;here&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;I've included a "testdata" directory along with the source code that contains empty files.&amp;nbsp; Thiles files all have the &lt;STRONG&gt;".clc.csv&lt;/STRONG&gt;" suffix.&amp;nbsp; This is what the CLCV applicatoin looks for. &lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1407434" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1407434.ashx" length="32266" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx">Beyond Hello World</category></item><item><title>Beyond Hello World - My First WPF Application (with source)</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/12/30/beyond-hello-world-my-first-wpf-application.aspx</link><pubDate>Sat, 30 Dec 2006 23:49:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1386274</guid><dc:creator>rgr</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1386274.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1386274</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1386274</wfw:comment><description>&lt;P&gt;My pet project for the holiday vacation has been writing a WPF application to view data from my code line counting tool CLC.EXE (soon to be released on &lt;A href="http://www.codeplex.com/" mce_href="http://www.codeplex.com/"&gt;Codeplex&lt;/A&gt;). CLC produces counts of lines, code, comments, and other statistics per file, per directory and for entire directory trees. When complete, the CLC data viewer (CLCV) will read a CLC data file and display various visualizations of the data such as a &lt;A href="http://en.wikipedia.org/wiki/Tree_mapping" mce_href="http://en.wikipedia.org/wiki/Tree_mapping"&gt;tree map&lt;/A&gt; (&lt;A href="http://www.panopticon.com/panopticon/Content;jsessionid=757C5F80F815D423CA80A782F9346456.tomcat1?id=268" mce_href="http://www.panopticon.com/panopticon/Content;jsessionid=757C5F80F815D423CA80A782F9346456.tomcat1?id=268"&gt;see also&lt;/A&gt;, &lt;A href="http://www.cs.umd.edu/hcil/treemap/" mce_href="http://www.cs.umd.edu/hcil/treemap/"&gt;and also&lt;/A&gt;), some pie charts and perhaps a histogram or two. 
&lt;P&gt;I’ve included the first working CLCV application shell in the attached zip file. This project builds in Visual Studio 2005 (any version). I used &lt;A href="http://www.microsoft.com/products/expression/en/Expression-Blend/default.mspx" mce_href="http://www.microsoft.com/products/expression/en/Expression-Blend/default.mspx"&gt;Microsoft Expression Blend&lt;/A&gt; to design the UI. The app-shell currently implements the application’s initial UI panel which gives the user the opportunity to open a new file, or select a recently opened file. This panel has the following features: 
&lt;UL&gt;
&lt;LI&gt;It keeps track of the most recently opened files, keeping the sorted with the most recently opened file at the top. It also manages the list&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;When CLCV starts, it deletes any files from the list that no longer exist&lt;/LI&gt;
&lt;LI&gt;When the user clicks on a file name that no longer exists, the name is removed from the list and the user is notified with a simple message box.&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;It uses XML serialization to save the recently opened file list.&lt;/LI&gt;
&lt;LI&gt;It saves the recent file list in the users application data directory (&lt;A href="http://blogs.msdn.com/oldnewthing/archive/2006/12/28/1374334.aspx" mce_href="http://blogs.msdn.com/oldnewthing/archive/2006/12/28/1374334.aspx"&gt;not under My Documents&lt;/A&gt;)&lt;/LI&gt;
&lt;LI&gt;When running on Windows Vista, it uses the new file open dialog box.&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;Note, to do this I used a really nicely implemented class from Sven Groot (&lt;A href="http://www.ookii.org/" mce_href="http://www.ookii.org/"&gt;Ookii.org&lt;/A&gt;). See his Vista style common file dialogs for .NET 2.0 (version 1.2) &lt;A href="http://www.ookii.org/software/" mce_href="http://www.ookii.org/software/"&gt;here&lt;/A&gt;.&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;I still have few things to do for CLCV’s initial UI panel: 
&lt;UL&gt;
&lt;LI&gt;The main UI needs a close button, but I haven’t yet figured out how to close a WPF window.&lt;/LI&gt;
&lt;LI&gt;The main UI panel needs to remember its position – currently it always appears in the center of the screen.&lt;/LI&gt;
&lt;LI&gt;For native applications, I usually create a console window for simple debug spew, but this doesn’t seem like the “.Net Way”. I need to figure out how to effectively use the Debug and Trace classes. For example, how do I get the debug and trace output when I’m not running the tool under the VS debugger? &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This is my very first foray with both WPF and C#.&amp;nbsp;&amp;nbsp; My only material exposure to managed code has been some utilities written in managed C++ so I could use the excellent &lt;A href="http://www.dundas.com/Products/Chart/NET/index.aspx" target=_blank mce_href="http://www.dundas.com/Products/Chart/NET/index.aspx"&gt;Dundas Charting&lt;/A&gt; products.&amp;nbsp; I used&amp;nbsp;managed C++ because I was in a hurry and needed&amp;nbsp;to&amp;nbsp;leverage&amp;nbsp;my existing class libraries (this worked well).&amp;nbsp;&lt;/P&gt;
&lt;P&gt;So I was pleasantly surprised that getting the UI shell and initial UI panel up and running was astonishingly easy to do; especially given that I could barely spell WPF and C# a week ago. The most amazing thing to me is how little code was needed is to do all this; 161 lines of C# code and about 80 lines or so of XAML. This is probably &lt;U&gt;at least&lt;/U&gt; an order of magnitude less code than it would take to do all this in native C++, even with a nice class library like &lt;A href="http://sourceforge.net/projects/wtl/" mce_href="http://sourceforge.net/projects/wtl/"&gt;WTL&lt;/A&gt; and &lt;A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_atl_ATL_Article_Overview.asp" mce_href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_atl_ATL_Article_Overview.asp"&gt;ATL&lt;/A&gt;. Not only is it less code, it was also easy to do – the compile-test turnaround time is super fast and the VS environment and debugger has deep knowledge about the C# language and .NET class libraries. &lt;A href="http://msdn.microsoft.com/vstudio/tour/vs2005_guided_tour/VS2005pro/Smart_Client/CPlusIntellisense.htm" mce_href="http://msdn.microsoft.com/vstudio/tour/vs2005_guided_tour/VS2005pro/Smart_Client/CPlusIntellisense.htm"&gt;Intelisense&lt;/A&gt; is really helpful and saved me loads of timing having to go back and look at documentation. VS’s C# editor is also quite good at finding syntax errors without compiling, saving more time. 
&lt;P&gt;I'm sure that someone will point out that even doing this right on top of Win32 in C could be done in a small amount of code.&amp;nbsp; I'm confident that is true in a limited way - but doing this with Win32, or even WTL/ATL would be a lot more code to get the same app behavior and features that are inherent in a C# and WPF application:&amp;nbsp;the blended background, the nice use of fonts and colors, transparent controls, the nice use of animation to highlight focus, the flow and layout capabilities that let windows be resized and maintain a useable and attractive layout.&amp;nbsp; 
&lt;P&gt;It took me about 15 minutes to develop a nice look and feel for the initial UI panel in Blend.&amp;nbsp;&amp;nbsp;There is simply no comparison here for native UI code - its all done by hand!&amp;nbsp;&amp;nbsp; The ability for UI designers to work efficiently with developers is a revolutionary capability. 
&lt;P&gt;There are other things&amp;nbsp;I like about WPF and .NET as well: 
&lt;UL&gt;
&lt;LI&gt;The WPF controls, their properties, methods, and events, seem much consistent and coherent than those from Windows.Forms.&lt;/LI&gt;
&lt;LI&gt;Microsoft Expression Blend is really easy to use and looks like it will be a great tool even at V1.0. &lt;/LI&gt;
&lt;LI&gt;If you use Blend to start Visual Studio, they work nicely together.&lt;/LI&gt;
&lt;LI&gt;I like Intelisense with native and managed C++, but wow, it sure is awesome with C# - the editor and dev environment know WAY more about C# than they do C++.&lt;/LI&gt;
&lt;LI&gt;I really like how well the XAML code and the C# partial classes fit together: The C# code can simply reference objects defined in XAML by their name which is defined by the “x:key” attribute.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;I did run into a few issues though: 
&lt;P&gt;Blend is a memory HOG. My system has 1GB of memory and running dev studio and blend together often cause a lot of paging. 
&lt;UL&gt;
&lt;LI&gt;The idea behind XAML is great, but I think the implementation in XML is clunky. It seems that every new thing at Microsoft uses XML. Is that always the right choice? Does a having a good hammer make every problem a nail?&lt;/LI&gt;
&lt;LI&gt;Data binding is still confusing to me…. It sure seems complicated, but I suspect that I just need to work on groking it… &lt;/LI&gt;
&lt;LI&gt;There is a TON of documentation on WPF, .NET 3.0 etc, but I still find it difficult to figure out how to do simple things.&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;For example, I needed a simple way to save and restore the recently used file list. The .NET Configuration class seemed like a good place to start. I spent about two hours dorking around with the Configuration” class before I gave up. It and its related classes are way too complicated and the examples were SuperCrapy™. So, I tried XML serialization. It took me about 15 minutes to get the save and restore functionality working – nice… J&lt;/LI&gt;
&lt;LI&gt;There seems to be a lot of name space overlap between .NET 3.0 (WPF) and Windows.Forms. Of course, this is why we have namespaces! But, the MSDN docs don’t really make it clear at the top level what is what – everything is under the class library hierarchy. &lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;Glork! Why in the heck do the .NET classes not support the new vista dialog boxes??? While Sven Groot’s classes are really handy (and nicely implemented), I shouldn’t have had to use them. Am I missing something? Is Sven missing something? Perhaps so… &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;It is&amp;nbsp;important to note that the benefits of WPF, C#, and managed code in general come with costs.&amp;nbsp; These applications are by their very nature larger in terms of memory and CPU utilization.&amp;nbsp; Our experience on the client performance team is that it takes a lot of work to ensure that a managed application launches quickly, remains responsive to user interactions, performs well in terms of throughput, scales well to large data sets, and is a "good citizen" in terms if system resource utilization. &lt;/P&gt;
&lt;P&gt;Good performance for managed applications is certainly possible, but developers need to be aware of the costs associated with managed applications, design for performance up front, and use performance tools (such as logging and profiling) to maintain good performance during the development process. &lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1386274" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/pigscanfly/attachment/1386274.ashx" length="28316" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx">Beyond Hello World</category></item><item><title>WPF Styles</title><link>http://blogs.msdn.com/pigscanfly/archive/2006/12/27/wpf-styles.aspx</link><pubDate>Wed, 27 Dec 2006 11:36:34 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1368521</guid><dc:creator>rgr</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/pigscanfly/comments/1368521.aspx</comments><wfw:commentRss>http://blogs.msdn.com/pigscanfly/commentrss.aspx?PostID=1368521</wfw:commentRss><wfw:comment>http://blogs.msdn.com/pigscanfly/rsscomments.aspx?PostID=1368521</wfw:comment><description>&lt;p&gt;One of the things I planned to do this holiday season was spend some time learning about &lt;a title="Windows Presentation Foundatoin - Wikipedia" href="http://en.wikipedia.org/wiki/Windows_Presentation_Foundation" target="_blank"&gt;Windows Presentation Foundation&lt;/a&gt; (here is the &lt;a title="Windows Presentation Foundation" href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/introducingwpf.asp" target="_blank"&gt;Microsoft link&lt;/a&gt;).&lt;/p&gt; &lt;p&gt;The first thing to&amp;nbsp;did was write a "&lt;a title="Hello World program" href="http://en.wikipedia.org/wiki/Hello_World" target="_blank"&gt;Hello World&lt;/a&gt;" program.&amp;nbsp; I wanted just&amp;nbsp;a simple window with a text box that said "Hello World".&amp;nbsp;&amp;nbsp; It was easy - &lt;a title="Microsoft Expression Blend" href="http://www.microsoft.com/products/expression/en/Expression-Blend/default.mspx" target="_blank"&gt;Expression Blend&lt;/a&gt; and &lt;a title="Visual Studio 2005" href="http://msdn2.microsoft.com/en-us/vstudio/default.aspx" target="_blank"&gt;Visual Studio 2005&lt;/a&gt; worked seamlessly together: it took about 5 minutes to get a basic "Hello World" program running - cool!&amp;nbsp;&amp;nbsp; It was relatively attractive and I set the background brush of the text box to Null so that it was transparent, giving the appearance of the text floating on the gradient background of the window. &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;I decided I wanted my little text box to change color when the mouse hovered over it.&amp;nbsp;&amp;nbsp; Then the &lt;a title="WPF Learning Curve" href="http://blogs.msdn.com/karstenj/archive/2006/04/05/curve.aspx" target="_blank"&gt;WPF learning curve&lt;/a&gt; started to kick in.&amp;nbsp;&amp;nbsp; Ah ah!&amp;nbsp; XAML styles and triggers are the answer....&amp;nbsp; &lt;/p&gt; &lt;p&gt;My first attempt was the following ..... bbzzzzzz..... it didn't work...&amp;nbsp; mmmmm&amp;nbsp;&lt;/p&gt; &lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns:x&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="attr"&gt;xml:lang&lt;/span&gt;&lt;span class="kwrd"&gt;="en-US"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="attr"&gt;x:Class&lt;/span&gt;&lt;span class="kwrd"&gt;="HelloWorld.MainWindow"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="TheMainWindow"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="attr"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;="RGR's First WPF App"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="640"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="480"&lt;/span&gt; &lt;span class="attr"&gt;ResizeMode&lt;/span&gt;&lt;span class="kwrd"&gt;="CanMinimize"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns:Microsoft_Windows_Themes&lt;/span&gt;&lt;span class="kwrd"&gt;="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt; &lt;span class="attr"&gt;TargetType&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="IsMouseOver"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF071D43"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.Background&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LinearGradientBrush&lt;/span&gt; &lt;span class="attr"&gt;EndPoint&lt;/span&gt;&lt;span class="kwrd"&gt;="1,0.5"&lt;/span&gt; &lt;span class="attr"&gt;StartPoint&lt;/span&gt;&lt;span class="kwrd"&gt;="0,0.5"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;GradientStop&lt;/span&gt; &lt;span class="attr"&gt;Color&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF0E0C0C"&lt;/span&gt; &lt;span class="attr"&gt;Offset&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;GradientStop&lt;/span&gt; &lt;span class="attr"&gt;Color&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF661212"&lt;/span&gt; &lt;span class="attr"&gt;Offset&lt;/span&gt;&lt;span class="kwrd"&gt;="0.207"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;LinearGradientBrush&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.Background&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="LayoutRoot"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;="8,8,8,0"&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="HelloTB"&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;="Top"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="64"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;                 &lt;span class="attr"&gt;BorderBrush&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Null}"&lt;/span&gt; &lt;span class="attr"&gt;FontSize&lt;/span&gt;&lt;span class="kwrd"&gt;="36"&lt;/span&gt;  &lt;span class="attr"&gt;Foreground&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF7E6E6E"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;                 &lt;span class="attr"&gt;IsUndoEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="False"&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox"&lt;/span&gt; &lt;span class="attr"&gt;TextWrapping&lt;/span&gt;&lt;span class="kwrd"&gt;="NoWrap"&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Text Box"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;                 &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;="0,0,0,0"&lt;/span&gt; &lt;span class="attr"&gt;IsReadOnly&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;                 &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Null}"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;div class="csharpcode"&gt;&amp;nbsp;&lt;/div&gt;
&lt;p&gt;After some dorking around, it finally dawned on me what was wrong - styles are hierarchical.&amp;nbsp;&amp;nbsp; The style trigger was indeed working, it simply wasn't overriding the Background="{x:Null}" attribute of the TextBox as it has a higher precedence than the style in the trigger.&amp;nbsp; The following example worked nicely:&amp;nbsp; Note that on line 13, the Null background characteristics is specified in the style, and not directly in the attributes of the TextBox itself.&amp;nbsp;&amp;nbsp; This allows the background "Setter" in the IsMouseOver trigger to work correctly as it and the default background have the same precedence. &lt;/p&gt;
&lt;div class="csharpcode"&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns:x&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="attr"&gt;xml:lang&lt;/span&gt;&lt;span class="kwrd"&gt;="en-US"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    &lt;span class="attr"&gt;x:Class&lt;/span&gt;&lt;span class="kwrd"&gt;="HelloWorld.MainWindow"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;    &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="TheMainWindow"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    &lt;span class="attr"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;="RGR's First WPF App"&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="640"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="480"&lt;/span&gt; &lt;span class="attr"&gt;ResizeMode&lt;/span&gt;&lt;span class="kwrd"&gt;="CanMinimize"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="attr"&gt;xmlns:Microsoft_Windows_Themes&lt;/span&gt;&lt;span class="kwrd"&gt;="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt; &lt;span class="attr"&gt;TargetType&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Null}"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="IsMouseOver"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF071D43"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;   &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.Background&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LinearGradientBrush&lt;/span&gt; &lt;span class="attr"&gt;EndPoint&lt;/span&gt;&lt;span class="kwrd"&gt;="1,0.5"&lt;/span&gt; &lt;span class="attr"&gt;StartPoint&lt;/span&gt;&lt;span class="kwrd"&gt;="0,0.5"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;GradientStop&lt;/span&gt; &lt;span class="attr"&gt;Color&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF0E0C0C"&lt;/span&gt; &lt;span class="attr"&gt;Offset&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;GradientStop&lt;/span&gt; &lt;span class="attr"&gt;Color&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF661212"&lt;/span&gt; &lt;span class="attr"&gt;Offset&lt;/span&gt;&lt;span class="kwrd"&gt;="0.207"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;LinearGradientBrush&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.Background&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="LayoutRoot"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt;&lt;span class="kwrd"&gt;="8,8,8,0"&lt;/span&gt; &lt;span class="attr"&gt;x:Name&lt;/span&gt;&lt;span class="kwrd"&gt;="HelloTB"&lt;/span&gt; &lt;span class="attr"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;="Top"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="64"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;                 &lt;span class="attr"&gt;BorderBrush&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Null}"&lt;/span&gt; &lt;span class="attr"&gt;FontSize&lt;/span&gt;&lt;span class="kwrd"&gt;="36"&lt;/span&gt;  &lt;span class="attr"&gt;Foreground&lt;/span&gt;&lt;span class="kwrd"&gt;="#FF7E6E6E"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;                 &lt;span class="attr"&gt;IsUndoEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="False"&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;="TextBox"&lt;/span&gt; &lt;span class="attr"&gt;TextWrapping&lt;/span&gt;&lt;span class="kwrd"&gt;="NoWrap"&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Text Box"&lt;/span&gt; &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;                 &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;="0,0,0,0"&lt;/span&gt; &lt;span class="attr"&gt;IsReadOnly&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;One thing I did find frustrating - especially as someone accustomed to native code development (I can barely spell ".NET") is how easy it is to hork up the XAML so that the resulting executable crashes.&amp;nbsp; For example,&amp;nbsp;this little code fragment crashings Hello World nicely...&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="x:Null"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;The buggy code compiled just fine in both Visual Studio 2005 and Expression Blend Beta-1.&amp;nbsp;&amp;nbsp; But when the Hello World program ran, it simple crashed.&amp;nbsp; Even more bothersome was the fact that the VS2005 debugger was useless.&amp;nbsp; When the program crashed, it popped up a useless dialog box with the wrong information.&amp;nbsp; The bug is simple, there are no curly braces "{ }" around the x:Null.&amp;nbsp; The correct snipit is:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Null}"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This isn't too surprising given that the task of processing the XAML code into a .NET object model is multi-step, happens at run-time and is complex.&amp;nbsp;&amp;nbsp;Given that XAML, WPF and the related technologies are so new, its amazing that the tools work as well as they do.&amp;nbsp; The caveat here is that don't expect as robust a development and debugging environment with XAML that we enjoy with native C++, Managed C++ or C#.&amp;nbsp; It will take some time (&lt;a title="Future orcas developer tools" href="http://msdn2.microsoft.com/en-us/vstudio/aa700830.aspx" target="_blank"&gt;Orcas&lt;/a&gt;??) but the Dev Div folks will get there!&lt;/p&gt;
&lt;p&gt;My next task is to make a program that does something useful.&amp;nbsp; I have a program that counts the lines of code in various languages (C++, C#, Perl, batch files, assembly language, etc).&amp;nbsp; I planto build a WPF program that displays a tree map of line counts for the entire Windows Vista code base.....&amp;nbsp; We'll see how WPF scales with this one.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1368521" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/Source+Code/default.aspx">Source Code</category><category domain="http://blogs.msdn.com/pigscanfly/archive/tags/WPF/default.aspx">WPF</category></item></channel></rss>