<?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 : Beyond Hello World</title><link>http://blogs.msdn.com/pigscanfly/archive/tags/Beyond+Hello+World/default.aspx</link><description>Tags: Beyond Hello World</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><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 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></channel></rss>