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

<channel>
	<title>&#60;code&#62;</title>
	<atom:link href="http://code.steepvalley.net/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://code.steepvalley.net</link>
	<description>a geeks rambling about SQL, VB, Deltek VISION and other stuff</description>
	<lastBuildDate>Thu, 12 Nov 2009 06:01:44 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Modifying Deltek Vision&#8217;s Standard Reports</title>
		<link>http://code.steepvalley.net/?p=3</link>
		<comments>http://code.steepvalley.net/?p=3#comments</comments>
		<pubDate>Wed, 11 Nov 2009 16:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Deltek Vision]]></category>
		<category><![CDATA[SQL Reporting]]></category>
		<category><![CDATA[Standard Reports]]></category>
		<category><![CDATA[Vision]]></category>

		<guid isPermaLink="false">http://code.steepvalley.net/?p=3</guid>
		<description><![CDATA[With Vision 6 we can finally use Microsoft SQL Reporting Services to create our own custom reports or even change existing ones. But modifying existing standard reports is not that easy as it seems in the first place.
 

The main reason for that is the following: I guess to provide the same functionality they had [...]]]></description>
			<content:encoded><![CDATA[<p>With Vision 6 we can finally use Microsoft SQL Reporting Services to create our own custom reports or even change existing ones. But modifying existing standard reports is not that easy as it seems in the first place.</p>
<p> <span id="more-3"></span>
</p>
<p>The main reason for that is the following: I guess to provide the same functionality they had in version 5 where you can define groupings and columns and their widths they had to resort to some wicked stuff in the code. I had to find this out the hard way when I tried to modify an existing standard report. When I looked closer into the select statement in the report I saw that this was a dummy statement that is nothing but a placeholder. </p>
<p>I assume, Deltek does the following: each standard report is bound to a specific options dialog in the custom properties of the report. This options dialog then creates a SQL statement on the fly, based on the report options you configure in VISION. It then replaces the statement in the report on runtime. Based on the named tables and columns then the dialog code goes through the report and applies any additional formatting just before the report is processed. </p>
<p>This has some major implications when you want to modify a report. I ran into the following issues:</p>
<ol>
<li>You are not able to add additional columns to the select statement (except the invoice report) because the select statement is created on-the-fly. </li>
<li>You get a runtime error every time you add a custom column to a table that VISION tries to modify at runtime based on the formatting options. </li>
</ol>
<p>Problem 1 is a tougher one. You actually have to create custom code in the report that connects back to the server and looks up additional data for each record of your report. I will have some details on that on my next blog entry</p>
<p>Problem 2 is easier to solve if the data is already supplied by the standard report and you just want to make the data visible. The trick here: you cannot modify the original table because you would run into that runtime error. So you do the following:</p>
<ul>
<li>Copy the original table and rename it </li>
<li>Hide the original table (don’t delete it because VISION will still try to modify it) </li>
<li>rename the copy and add or remove any column </li>
</ul>
<p>What this does is the following: it connects to the same dataset as the original table so you can access the on-the-fly data select that VISION sent in. But because it will only try to alter the layout of the original table you don’t run into any errors. Biggest draw-back: any formatting you specify in the options dialog will have no effect to your table copy so you will have to do that manually and hard-coded.</p>
<p>After you did your modifications, you can upload the report either as custom report or simply replace the standard report. The beauty of uploading it as a custom report: you still reference the original options dialog. So when you start the report you get the same options dialog as the original – just with some different behaviour.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=3</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Book &quot;Windows Developer Power Tools&quot; Out Now</title>
		<link>http://code.steepvalley.net/?p=16</link>
		<comments>http://code.steepvalley.net/?p=16#comments</comments>
		<pubDate>Mon, 01 Oct 2007 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[White Papers]]></category>

		<guid isPermaLink="false">/post/2007/10/WinDevPowerTools.aspx</guid>
		<description><![CDATA[
I&#39;m proud to anounce that the XP Common Controls are part of the newly released book &#34;Windows Developer Power Tool&#34; by James Avery and Jim Holmes. This book contains references to over 170 free and open source tools, components and frameworks, all of them coming with a mini user&#39;s guide. 
Please check out their homepage [...]]]></description>
			<content:encoded><![CDATA[<p>
I&#39;m proud to anounce that the XP Common Controls are part of the newly released book &quot;Windows Developer Power Tool&quot; by James Avery and Jim Holmes. This book contains references to <em>over 170 free and open source tools, components and frameworks</em>, all of them coming with a mini user&#39;s guide. <br />
Please check out their homepage at <a href="http://www.windevpowertools.com/"><font color="#669966">http://www.windevpowertools.com</font></a> or buy the <a style="color: #666666; text-decoration: none" href="http://www.makemoney-earnmoney.com" target="_blank">book</a> here: <a href="http://www.amazon.com/exec/obidos/ASIN/0596527543/infozerk-20"><font color="#669966">http://www.amazon.com/exec/obidos/ASIN/0596527543/infozerk-20</font></a> &#8211; it will save you a lot of <a style="color: #666666; text-decoration: none" href="http://www.makemoney-earnmoney.com" target="_blank">time and money</a> when creating your next .net project. <br />
My thanks to Jim and James for asking me to contribute to this book.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=16</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Copying Your Database Documentation From One Database To Another</title>
		<link>http://code.steepvalley.net/?p=17</link>
		<comments>http://code.steepvalley.net/?p=17#comments</comments>
		<pubDate>Fri, 01 Jun 2007 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[SQL]]></category>
		<category><![CDATA[White Papers]]></category>

		<guid isPermaLink="false">/post/2007/06/CopyDBDoc.aspx</guid>
		<description><![CDATA[We are using Red Gates SQLDoc (http://www.red-gate.com) tool to document our databases and it works just fine. But as a matter of fact we do our documentations on the test server not the real server. And then a problem arises.
SQLDoc has no tool to copy the documentation from one DB to another.
And that&#8217;s the problem [...]]]></description>
			<content:encoded><![CDATA[<p>We are using Red Gates SQLDoc (<a href="http://www.red-gate.com/"><span style="color: #669966;">http://www.red-gate.com</span></a>) tool to document our databases and it works just fine. But as a matter of fact we do our documentations on the test server not the real server. And then a problem arises.</p>
<p>SQLDoc has no tool to copy the documentation from one DB to another.</p>
<p>And that&#8217;s the problem because SQLDoc (and other tools including SQL Management Console itself) put the documentation text into the extended properties of SQL Server 2000 and SQL Server 2005, so you cannot simply copy the documented tables, procedures or functions within the help file. And documenting on the master DB did not prove usefull for us.<span id="more-17"></span></p>
<p>So I checked the internals of the extended properties on SQL Server and found out that it uses the procedures sp_addextendedproperty and sp_dropextendedproperty and the internal, undocumented system table SYSPROPERTIES to save the documentation text onto the database. The SQL-Script below will extract your documentation and produce the needed procedure calls in the result window. Simply copy the text from the result window and execute it on the other database. The other database has to have the same schema of course! And because the existence of an extended property is not checked before you will receive some errors when executing the sp_drop&#8230; procedures, but this has no effect on the db.</p>
<p>Here&#8217;s the script:</p>
<blockquote><p> </p>
<p><span style="font-family: consolas; font-size: 10pt">DECLARE @name NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@value NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level0type NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level0name NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level1type NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level1name NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level2type NVARCHAR(4000), </span><span style="font-family: consolas; font-size: 10pt"><span>         </span>@level2name NVARCHAR(4000)</span><span style="font-family: consolas; font-size: 10pt"><span>         </span></span><span style="font-family: consolas; font-size: 10pt">DECLARE @statement NVARCHAR(4000)</span><span style="font-family: consolas; font-size: 10pt">DECLARE cloop CURSOR LOCAL for</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>SELECT<span>   </span>S.NAME AS NAME,</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>REPLACE(CAST(S.VALUE AS NVARCHAR(4000)), &#8221;&#8221;, &#8221;&#8221;&#8221;) AS VALUE, </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>&#8216;USER&#8217; AS LEVEL0TYPE,</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>&#8216;dbo&#8217; AS LEVEL0NAME,</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>CASE O.XTYPE </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span><span>         </span>WHEN &#8216;U&#8217; THEN &#8216;TABLE&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>WHEN &#8216;P&#8217; THEN &#8216;PROCEDURE&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>WHEN &#8216;FN&#8217; THEN &#8216;FUNCTION&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>                          </span>WHEN &#8216;TF&#8217; THEN &#8216;FUNCTION&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>WHEN &#8216;IF&#8217; THEN &#8216;FUNCTION&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>                          </span>WHEN &#8216;V&#8217; THEN &#8216;VIEW&#8217; END </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>AS LEVEL1TYPE,</span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>O.NAME AS LEVEL1NAME,</span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>CASE S.TYPE </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>WHEN 4 THEN &#8216;COLUMN&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>ELSE &#8216;NULL&#8217; END </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>AS LEVEL2TYPE,</span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>CASE </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>WHEN ISNULL(C.NAME, &#8221;) = &#8221; THEN &#8216;NULL&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>                 </span>ELSE C.NAME END </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>AS LEVEL2NAME</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>FROM<span>     </span>SYSPROPERTIES S</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>JOIN SYSOBJECTS O ON S.ID = O.ID</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>LEFT JOIN SYSCOLUMNS C ON S.ID = C.ID AND S.SMALLID = C.COLORDER</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>&#8211;LEFT JOIN SYSINDEXES I ON S.ID = I.ID AND S.SMALLID = I.INDID</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>WHERE<span>    </span>S.NAME = &#8216;MS_Description&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>ORDER BY 5,6,7,8</span><span style="font-family: consolas; font-size: 10pt"><span>         </span></span><span style="font-family: consolas; font-size: 10pt">OPEN cloop</span></p>
<p class="MsoNormal" style="margin: 7.5pt 0cm; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"><span style="font-family: consolas; font-size: 10pt">FETCH next FROM cloop INTO @name, @value, @level0type, @level0name, @level1type, </span></p>
<p><span style="font-family: consolas; font-size: 10pt">@level1name, @level2type, @level2name</span><span style="font-family: consolas; font-size: 10pt"> </span><span style="font-family: consolas; font-size: 10pt">WHILE @@FETCH_STATUS = 0</span><span style="font-family: consolas; font-size: 10pt">BEGIN</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>&#8211;drop property</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>SET @statement =</span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>&#8216;exec sp_dropextendedproperty N&#8221;&#8217; + @name + &#8221;&#8217;, &#8221;&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level0type +  &#8221;&#8217;, &#8221;&#8217; + @level0name + &#8221;&#8217;, &#8221;&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level1type +  &#8221;&#8217;, &#8221;&#8217; + @level1name + &#8221;&#8217;, &#8221;&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level2type +  &#8221;&#8217;, &#8221;&#8217; + @level2name + &#8221;&#8221;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span></span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>SET @statement = REPLACE( @statement, &#8221;&#8217;NULL&#8221;&#8217;, &#8216;NULL&#8217;)</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>PRINT &#8216;/*&#8217; + @level1type + &#8216;: &#8216; + @level1name + &#8216;*/&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>PRINT @statement</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>PRINT &#8216;GO&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>&#8211;add property</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>SET @statement = </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>&#8216;exec sp_addextendedproperty N&#8221;&#8217; + @name + &#8221;&#8217;, N&#8221;&#8217; + @value + &#8221;&#8217;, &#8221;&#8217; </span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level0type +  &#8221;&#8217;, &#8221;&#8217; + @level0name + &#8221;&#8217;, &#8221;&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level1type +  &#8221;&#8217;, &#8221;&#8217; + @level1name + &#8221;&#8217;, &#8221;&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>+ @level2type +  &#8221;&#8217;, &#8221;&#8217; + @level2name + &#8221;&#8221;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span></span><span style="font-family: consolas; font-size: 10pt"><span>                 </span>SET @statement = REPLACE( @statement, &#8221;&#8217;NULL&#8221;&#8217;, &#8216;NULL&#8217;)</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>&#8211;PRINT &#8216;/*&#8217; + @level1type + &#8216;: &#8216; + @level1name + &#8216;*/&#8217;</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>PRINT @statement</span><span style="font-family: consolas; font-size: 10pt"><span>         </span><span>         </span>PRINT &#8216;GO&#8217;</span><span style="font-family: consolas; font-size: 10pt"> </span></p>
<p class="MsoNormal" style="margin: 7.5pt 0cm; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"><span style="font-family: consolas; font-size: 10pt"><span>                 </span>FETCH next FROM cloop INTO @name, @value, @level0type, @level0name, </span></p>
<p><span style="font-family: consolas; font-size: 10pt">                       @level1type, @level1name, @level2type, @level2name</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>END</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>CLOSE cloop</span><span style="font-family: consolas; font-size: 10pt"><span>         </span>DEALLOCATE cloop</span></p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=17</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XPCC / XP Common Controls</title>
		<link>http://code.steepvalley.net/?p=18</link>
		<comments>http://code.steepvalley.net/?p=18#comments</comments>
		<pubDate>Sun, 01 Apr 2007 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[White Papers]]></category>
		<category><![CDATA[XPCC]]></category>

		<guid isPermaLink="false">/post/2007/04/XPCC.aspx</guid>
		<description><![CDATA[When I was starting to develop in VS.net I wanted that nice XP-Look for all of my programs. The problem is, that Visual Studio shipped without most of them. The most missed controls where the Taskbox/Taskbar control and the Grouped ListView Contol.
I ran into implementations of some of the controls on the internet (namely vbAccelerator [...]]]></description>
			<content:encoded><![CDATA[<p>When I was starting to develop in VS.net I wanted that nice XP-Look for all of my programs. The problem is, that Visual Studio shipped without most of them. The most missed controls where the Taskbox/Taskbar control and the Grouped ListView Contol.<br />
I ran into implementations of some of the controls on the internet (namely vbAccelerator and the TaskVision Sample on <a href="http://www.windowsforms.net/"><span style="color: #669966;">http://www.windowsforms.net</span></a>) and into a document provided by Microsoft named &#8220;Windows XP Design Guidelines&#8221;. This document provides detailed information on some of the new controls and I started to recreate some of these controls for VS.net (with hints and help from the sites mentioned above &#8211; thank you again!) <span id="more-18"></span>The one feature I wanted to have with the XP Controls was theming. But since it always needed some direct dll calls to uxtheme.dll I wrote my own theming dll. This has some positive and some negative effects.</p>
<h2>Positive:</h2>
<p>It runs on any OS that supports the .net-Framework; means it will run on non-XP Systems like Win95 and Win2000. That said, I must also tell you that the theme listener and the grouping and tiling of the XPListGroup won’t work without Win XP.<br />
I didn’t have to write a lot of API-calls <img src='http://code.steepvalley.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h2>Negative:</h2>
<p>If Microsoft introduces a new theme or you download one from the internet, the controls will not support this one until it’s hardwired into the code.<br />
As a workaround for the negative part I have exposed all properties of the theming formats to the IDE so you can define any combination of formats you want.<br />
The collection of controls grew over time and include now balloon tips, cue banners, a textbox provider, panes, &#8230;<br />
The newest addition are the Windows Forms Stylesheet (a separate project before) that will allow you change properties of your forms and controls at runtime, based on a xml definition file (similar to CSS in HTML).</p>
<h2>Source Code</h2>
<p>You can find the XPCC code and controls at <a href="http://www.codeplex.com/xpcc"><span style="color: #669966;">http://www.codeplex.com/xpcc</span></a></p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=18</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Synchronizing UI Elements With A Command Class</title>
		<link>http://code.steepvalley.net/?p=19</link>
		<comments>http://code.steepvalley.net/?p=19#comments</comments>
		<pubDate>Thu, 01 Mar 2007 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">/post/2007/03/CommandClass.aspx</guid>
		<description><![CDATA[Synchronizing UI Elements
When designing common Windows Forms Application, it always turns out to be a bit of a hassle to synchronize different UI elements like a MenuItem and a Toolbar Item that execute (or should execute) the same code or should be activated and deactivated at the same time. 
Using Commands
One Solution to this problem [...]]]></description>
			<content:encoded><![CDATA[<h2>Synchronizing UI Elements</h2>
<p>When designing common Windows Forms Application, it always turns out to be a bit of a hassle to synchronize different UI elements like a MenuItem and a Toolbar Item that execute (or should execute) the same code or should be activated and deactivated at the same time. <span id="more-19"></span></p>
<h2>Using Commands</h2>
<p>One Solution to this problem is to delegate the work to a command class and then attach one or more UI elements to this class. The Command Class will then be in charge of executing commands, enable, disable, hide or show the attached elements.</p>
<p>In a future version I will provide a command extender that can be dragged onto a form and UI elements can then be attached to it. Meanwhile you will find some code that will allow you to use those command classes in code.</p>
<p>Using command classes in code has advantages too. You can create your very own application model with all the commands you need in your app as you will see in the demo app.</p>
<h2>The Command Class</h2>
<p>The Command Class itself contains a collection of attached components, some properties that will be explained shortly and some events that are used to inform the commands containing class of any changes in the command class.</p>
<h2>Public Properties</h2>
<p>There are three Properties (PropagateEnabled, PropagateVisible, PropagateText) that will allow one attached component to change the command’s Enabled, Visible or Text Property which will in turn propagate those changes to all other attached components. Setting the Visible and Enabled Property directly on the command object will always result in the propagation of the property value to all attached components.</p>
<p>The standard behaviour of the Text property is to NOT PROPAGATE to all attached components because this could end in some „funny“ scenarios because you could also attach textboxes to the command class. On the other hand, propagating the Text can be useful if the menu item or button should display certain states and be constant over all attached components.</p>
<blockquote><p>Dim WithEvents MyCommand as New Command</p>
<p>MyCommand.PropagateEnabled = True</p>
<p>MyCommand.Add( menuItem1 )</p>
<p>MyCommand.Add( toolbarItem1 )</p>
<p>&#8230;</p>
<p>&#8216;this will disable menuItem1 AND toolbaritem1</p>
<p>menuItem1.Enabled = False</p></blockquote>
<h2>Public Methods</h2>
<p>The Add- and Remove-Method allow you to attach any Control or ToolStripItem to a command. Because most controls support an Enabled or Visible property, attaching textboxes, buttons and/or menu items to one command you can design highly interactive UI that could disable or hide a wide range or elements by simply setting one command property.</p>
<p>Calling the Clear method will remove all attached components at once.</p>
<p>The Execute Method will invoke the Click handler which can be intercepted in the parent class and the apropriate code can be executed for this command.</p>
<h2>Using the Command Classes</h2>
<p>The code includes a very simple editor application that will allow you to open, save and edit a text file. The editor’s behaviour is not programmed into the form. The project has a shared class called EditorApplication that includes all methods and commands that can be executed from the editor. It also supports some events that the editor can use to show changes.</p>
<h2>The EditorApplicationClass</h2>
<p>As mentioned before, all the behaviour is in this class. All methods and events are declared shared so that the class must not be instantiated but can be used immediately in the main form. The class has a child class called Commands where all available commands for this application are defined. The class also includes the event handling of each command which in return calls a method of the EditorApplication.</p>
<blockquote><p>Public Class EditorApplication</p>
<p>Public Class Commands</p>
<p>Public Shared WithEvents OpenFile As New Command</p>
<p>Public Shared WithEvents SaveFile As New Command</p>
<p>Public Shared WithEvents CloseFile As New Command</p>
<p>Public Shared WithEvents NewFile As New Command</p>
<p>Public Shared WithEvents ChangeFont As New Command</p>
<p>Public Shared WithEvents SaveFileAs As New Command</p>
<p>Private Shared Sub ChangeFont_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ChangeFont.Click</p>
<p>EditorApplication.ChangeFont()</p>
<p>End Sub</p>
<p>Private Shared Sub CloseFile_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles CloseFile.Click</p>
<p>EditorApplication.CloseFile()</p>
<p>End Sub</p>
<p>&#8230;</p>
<p>End Class</p>
<p>Public Shared Sub CloseFile()</p>
<p>If Not CheckFile() Then Exit Sub</p>
<p>CurrentFile = &#8220;&#8221;</p>
<p>Content = &#8220;&#8221;</p>
<p>IsDirty = False</p>
<p>IsNew = False</p>
<p>Commands.SaveFile.Enabled = False</p>
<p>Commands.SaveFileAs.Enabled = False</p>
<p>Commands.CloseFile.Enabled = False</p>
<p>End Sub</p>
<p>&#8230;</p>
<p>End Class</p></blockquote>
<p>The EditorApplication keeps track of the current file, the current content and any status changes and raises events or changes commands accordingly.</p>
<h2>The Editor Form</h2>
<p>The editor form itself is very simple. You can define all UI elements by dragging them from the toolbox. In a next step you go to the Load event of the form and attach every UI elemtent to the related command object of the application class. You then hook up any EditorApplication Event you’re interested in and then you’re ready to go.</p>
<blockquote><p>Private Sub AttachCommands()</p>
<p>EditorApplication.Commands.ChangeFont.Add(ChangeFontToolStripMenuItem)</p>
<p>EditorApplication.Commands.ChangeFont.Add(tsChangeFont)</p>
<p>EditorApplication.Commands.CloseFile.Add(CloseToolStripMenuItem)</p>
<p>EditorApplication.Commands.NewFile.Add(NewToolStripMenuItem)</p>
<p>EditorApplication.Commands.NewFile.Add(tsNew)</p>
<p>EditorApplication.Commands.OpenFile.Add(OpenToolStripMenuItem)</p>
<p>EditorApplication.Commands.OpenFile.Add(tsOpen)</p>
<p>EditorApplication.Commands.SaveFile.Add(SaveToolStripMenuItem)</p>
<p>EditorApplication.Commands.SaveFile.Add(tsSave)</p>
<p>EditorApplication.Commands.SaveFileAs.Add(SaveAsToolStripMenuItem)</p>
<p>End Sub</p>
<p>Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load</p>
<p>AttachCommands()</p>
<p>AddHandler EditorApplication.FileChanged, AddressOf OnFileChanged</p>
<p>AddHandler EditorApplication.ContentChanged, AddressOf OnContentChanged</p>
<p>AddHandler EditorApplication.FontChanged, AddressOf OnContentFontChanged</p>
<p>AddHandler EditorApplication.StatusChanged, AddressOf OnStatusChanged</p>
<p>rtfText.Enabled = False</p>
<p>EditorApplication.Commands.SaveFile.Enabled = False</p>
<p>EditorApplication.Commands.SaveFileAs.Enabled = False</p>
<p>EditorApplication.Commands.CloseFile.Enabled = False</p>
<p>EditorApplication.CurrentFont = Me.rtfText.Font</p>
<p>End Sub</p>
<p>&#8230;</p>
<p>Private Sub OnStatusChanged(ByVal sender As Object, ByVal e As EventArgs)</p>
<p>Me.Text = String.Format(&#8221;{0}{1}&#8221;, EditorApplication.CurrentFile, IIf(EditorApplication.IsDirty, &#8220;*&#8221;, &#8220;&#8221;))</p>
<p>If EditorApplication.CurrentFile = &#8220;&#8221; And EditorApplication.IsNew = False Then</p>
<p>rtfText.Enabled = False</p>
<p>End If</p>
<p>End Sub</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=19</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Generic Server-Side Paging with MS SQL Server</title>
		<link>http://code.steepvalley.net/?p=20</link>
		<comments>http://code.steepvalley.net/?p=20#comments</comments>
		<pubDate>Sun, 01 Oct 2006 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[White Papers]]></category>

		<guid isPermaLink="false">/post/2006/10/GenericPaging.aspx</guid>
		<description><![CDATA[Paging through a resultset seems to be a common problem with Winforms and Webforms. While you could do it all clientside with loading your complete resultset into a Dataset and then page through it, this will only be reasonable with a small amount of data. If you try to do this with resultsets of more [...]]]></description>
			<content:encoded><![CDATA[<p>Paging through a resultset seems to be a common problem with Winforms and Webforms. While you could do it all clientside with loading your complete resultset into a Dataset and then page through it, this will only be reasonable with a small amount of data. If you try to do this with resultsets of more than 1000 rows, the dataset will soon be consuming all of your memory or bandwith when transfering the data from the SQL Server to the Dataset on the client. <span id="more-20"></span>The most convenient way of handling large chunks of data would be to page through them on the server side. But there seemed to be no good reusable solution for MS SQLServer 2000. I&#8217;ve seen solutions with &#8216;Yukon&#8217; and the ROWNUMBER()-function or solutions that saves the resultset for each user in a separate table and then looping through it but I haven&#8217;t seen any view-like solution to this.</p>
<p>Here&#8217;s mine: I created a procedure that takes the displayed fields, the table(s), the filter (or where clause), the grouping, the sorting clause, the page size (rows per page) and the requested page as parameters.</p>
<p>The procedure then creates a a sub-select that returns all rows from the first row to the [pagesize] * [requested page] row. Then the procedure creates a select that returns the bottom n rows (page size) by flipping the sort order and returning the TOP n rows of the subselect. In the last step the Resultset is sorted once more by the initial sorting clause to get the rows in the requested order.</p>
<p>You must provide at least one sorting criteria to make it work! After that you can run this procedure on any database you have. You can also join tables simply by adding the join statement into the table parameter, but DO NOT use the table identifier with the fields parameter (like &#8216;Suppliers.CompanyName&#8217;). It&#8217;s better to always use a defined View over your paged data..</p>
<p>Hope you like it:</p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ************************************************************************<br />
&#8211; delete any existing procedure<br />
&#8211; ************************************************************************<br />
if exists (select 1 from sysobjects where name = &#8217;sp_genericPaging&#8217; and xtype = &#8216;P&#8217;)<br />
begin<br />
drop procedure sp_genericPaging<br />
end </span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;"> </span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">GO</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">create procedure sp_genericPaging<br />
@fields nvarchar(4000),<br />
@table nvarchar(4000),<br />
@filter nvarchar(4000) = &#8221;,<br />
@grouping nvarchar(4000) = &#8221;,<br />
@sort nvarchar(4000) = &#8221;,<br />
@pageSize int = 100,<br />
@page int = 1<br />
as</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">set nocount on<br />
declare @statement nvarchar(4000)</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ****************************************************************************<br />
&#8211; prepare a subselect for the last matches<br />
&#8211; ****************************************************************************<br />
set @statement =<br />
&#8216;(SELECT TOP &#8216; + cast((@pageSize * (@page)) as varchar(100)) + &#8216; &#8216; + @fields +<br />
&#8216; FROM &#8216; + @table +<br />
case when isnull(@filter,&#8221;) != &#8221; then &#8216; WHERE &#8216; + @filter else &#8221; end +<br />
case when isnull(@grouping,&#8221;) != &#8221; then &#8216; GROUP BY &#8216; + @filter else &#8221; end +<br />
case when isnull(@sort, &#8221;) != &#8221; then &#8216; ORDER BY &#8216; + @sort else &#8221; end + &#8216;) SUBSEL&#8217;</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ****************************************************************************<br />
&#8211; flip the sort clause<br />
&#8211; ****************************************************************************<br />
declare @pos int, @idx int, @len int, @substr nvarchar(250), @retsort nvarchar(400)</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">set @retsort = &#8221;<br />
set @pos = 1<br />
set @idx = 1</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">if len(@sort) &gt; 0<br />
begin<br />
while @idx &gt; 0<br />
begin<br />
&#8211; find commas<br />
set @idx = charindex(&#8217;,', @sort, @pos)<br />
&#8211;check length<br />
if @idx = 0<br />
set @len = len(@sort) &#8211; @pos + 1<br />
else<br />
set @len = @idx &#8211; @pos<br />
&#8211; cut out criteria<br />
set @substr = substring(@sort, @pos, @len)<br />
&#8211; reset positioning<br />
set @pos = @pos + @len + 1<br />
&#8211; change sorting<br />
if charindex(&#8217;desc&#8217;, @substr) &gt; 0<br />
begin<br />
set @substr = replace(@substr, &#8216;desc&#8217;, &#8216;asc&#8217;)<br />
end<br />
else if charindex(&#8217;asc&#8217;, @substr) &gt; 0<br />
begin<br />
set @substr = replace(@substr, &#8216;asc&#8217;, &#8216;desc&#8217;)<br />
end<br />
else<br />
begin<br />
set @substr = @substr + &#8216; desc&#8217;<br />
end<br />
&#8211; recreate flipped sorting<br />
set @retsort = @retsort + case when len(@retsort) &gt; 0 then &#8216;, &#8216; else &#8221; end + @substr<br />
end<br />
end<br />
else<br />
begin<br />
set @retsort = &#8221;<br />
end</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ***************************************************************************<br />
&#8211; add the paging select<br />
&#8211; ***************************************************************************<br />
set @statement =<br />
&#8216;(SELECT TOP &#8216; + cast(@pageSize as varchar(100)) + &#8216; &#8216; + @fields +<br />
&#8216; FROM &#8216; + @statement +<br />
case when isnull(@retsort, &#8221;) != &#8221; then &#8216; ORDER BY &#8216; + @retsort else &#8221; end + &#8216;) PAGESEL&#8217;</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ***************************************************************************<br />
&#8211; flip the sorting once more to get the correct sorting<br />
&#8211; ***************************************************************************<br />
set @statement =<br />
&#8216;SELECT &#8216; + @fields +<br />
&#8216; FROM &#8216; + @statement +<br />
case when isnull(@sort, &#8221;) != &#8221; then &#8216; ORDER BY &#8216; + @sort else &#8221; end + &#8221;</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">&#8211; ****************************************************************************<br />
&#8211; execute the selection and return the resultset<br />
&#8211; ****************************************************************************<br />
exec(@statement)</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">GO</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">/*testselect*/</span></p>
<p><span style="font-family: Consolas; color: #008000; font-size: x-small;">exec sp_genericPaging<br />
&#8216;ProductID, ProductName, CompanyName, UnitPrice&#8217;, &#8211;feldnamen<br />
&#8216;Products join Suppliers on Products.SupplierID = Suppliers.SupplierID&#8217;, &#8211;tabelle(n)<br />
&#8221;, &#8211;filter (WHERE)<br />
&#8221;, &#8211;grouping<br />
&#8216;ProductID&#8217;, &#8211;sort<br />
20, &#8211;pagesize<br />
3 &#8211;currentpage</span></p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=20</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Owner Drawing Your Textboxes</title>
		<link>http://code.steepvalley.net/?p=7</link>
		<comments>http://code.steepvalley.net/?p=7#comments</comments>
		<pubDate>Sat, 08 Jul 2006 05:39:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[VB.net]]></category>
		<category><![CDATA[Windows Forms]]></category>
		<category><![CDATA[Controls]]></category>
		<category><![CDATA[Owner Drawn]]></category>
		<category><![CDATA[Winforms]]></category>

		<guid isPermaLink="false">http://code.steepvalley.net/?p=7</guid>
		<description><![CDATA[To give your textboxes a distinctive look has always been a hassle. In the old VB6 days it was almost not possible. The only thing you could do, was to incorporate the textbox into a ActiveX-control and set the looks of the ActiveX-Control.
With the advent of VB.net there seem to be 3 distinctive ways to [...]]]></description>
			<content:encoded><![CDATA[<p>To give your textboxes a distinctive look has always been a hassle. In the old VB6 days it was almost not possible. The only thing you could do, was to incorporate the textbox into a ActiveX-control and set the looks of the ActiveX-Control.</p>
<p>With the advent of VB.net there seem to be 3 distinctive ways to accomplish this task. With the XPTextbox-control I tried them all and will explain them shortly and point out the advantages and disadvantages.</p>
<p> <span id="more-7"></span><br />
<h3>Inherit a Textbox </h3>
<p>The most elegant way of enhancing the textbox would be inheritance of course. This will give you everything from the textbox plus all the things you add to your derived class.</p>
<p>This works great for any functionality (like input validation, … ) that does not impact the visual design of the textbox. Because of the distinctive way a textbox is incorporated into the OS (especially with WinXP), you do almost nothing to display a different border style, border color or other visual elements inside the textbox.</p>
<p>Because of these problems I had to skip this approach and try the next one</p>
<h3>Incorporate a Textbox in a Usercontrol </h3>
<p>The next thing I tried, was the same approach you’d take in VB6. I created a user-control that hosts a textbox and all the “skinning” and UI design takes place inside the user-control but outside the textbox itself.</p>
<p>This approach has some advantages like the capsulation of the control and the design-time interaction in VS.net. You only have to override the OnPaint-Method of the user-control and paint whatever you like into the user control.</p>
<p>It has one big disadvantage though: you don’t inherit the textbox, you just incorporate it. To give the developer the same properties, methods and events he is used to from the textbox control you have to wrap every single call or property of the textbox to the user control. This is a tedious task and also quite error prone.</p>
<p>I have done this to some extend with the XPTextBox control of the XPCommonControls suite. It draws a nice rounded border and a focus marker (an orange line like the tab control) when appropriate. But I did not wire up all the properties and methods and events from the text box to the user control. And a lot of mail came in requesting this or that property or method (Including databinding).</p>
<p>And since I don’t like to produce a lot of senseless source code I tried to find another solution to this problem</p>
<h3>Using an ExtenderProvider </h3>
<p>And while looking for a way of to give the themed controls of the XPCommonControls suite the ability to adapt automatically to any new theme in the OS I found the <a href="http://www.skybound.ca/"><font color="#669966">Skybound Website</font></a>. Not only do they provide a .net wrapper for the uxTheme calls, they also extend the theming support of any .net Form.</p>
<p>They do so by using an ExtenderControl and then drawing the themes according to the control type.</p>
<p>I found this idea to be a very clever way of doing your custom painting. The approach has all the advantages and almost none of the disadvantages of the other approaches.</p>
<p>You write an extender control that hooks up to your form and then checks for any control type you’d like to owner-draw. You can even add a property that tells the extender if this instance of a control should be drawn or not.</p>
<p>You then override the OnPaint event of your parent form and draw any shape around the textboxes.</p>
<p>This way the developer has full control of any method/property of the textbox (since it’s still the original textbox type provided by Microsoft) but you can add any custom drawing to the form the textbox is attached to.</p>
<p>See the XPCommonControls XPTextBoxProvider class for an implementation of this approach.</p>
<h3>Conclusion </h3>
<p>As you can see, there are advantages and disadvantages to all approaches from above. But since the .net Framework offers us the possibility to write provider classes this will be my favorite way to add advanced behaviour to any standard control.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=7</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementing Renderers Into Your Custom Controls</title>
		<link>http://code.steepvalley.net/?p=21</link>
		<comments>http://code.steepvalley.net/?p=21#comments</comments>
		<pubDate>Fri, 07 Jul 2006 17:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[White Papers]]></category>

		<guid isPermaLink="false">/post/2006/07/Renderers.aspx</guid>
		<description><![CDATA[When I first played around with the new .net 2.0 controls, I was fascinated by the ToolStrip-Control and its endless possibilities to render it to your will by using the new Renderer property.
Having this kind of approach on any user-defined control would give the developer a powerful way of designing his application without forcing him [...]]]></description>
			<content:encoded><![CDATA[<p>When I first played around with the new .net 2.0 controls, I was fascinated by the ToolStrip-Control and its endless possibilities to render it to your will by using the new Renderer property.</p>
<p>Having this kind of approach on any user-defined control would give the developer a powerful way of designing his application without forcing him to play around in the inner workings of the source. <span id="more-21"></span></p>
<p>So I decided to plunge into this topic and out came the little example you will see here.</p>
<p>(I’m also planning to recode most of the XPCommonControls to use this new Rendering approach)</p>
<h2>How To</h2>
<p>So I did some research on the topics of Renderers, RenderModes and other properties of the ToolStrip control and put together a little „recipe“ to cook up my own Rendering support for basically any user control.</p>
<h4><span style="color: #669966;">Class Structure</span></h4>
<p>If you want to support Rendering in your control you will have to build a lot of sattelite classes to get it working. In the following table I list all the classes I added for this little example (simply exchange the [Control] with your control’s name)</p>
<h5><span style="color: #669966;">[Control]</span></h5>
<p>Your UserControl that should be rendered.</p>
<p>You should split the control’s layout in multiple items so that the user must not alter the whole rendering but specific parts of it.</p>
<p>You will need a RenderMode property and a Renderer property of type [Control]Renderer that is set to the default rendering class (e.g. [Control]SystemRenderer.</p>
<p>You will then have to override the OnPaint method and call every Draw[Item] of the base renderer.</p>
<p> </p>
<p>Protected Overrides Sub OnPaint( ByVal e As System.Windows.Forms.PaintEventArgs)<br />
MyBase.OnPaint(e)<br />
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality<br />
_renderer.DrawBackground( New BoxControlRenderEventArgs(e.Graphics, Me))<br />
_renderer.DrawBorder( New BoxControlRenderEventArgs(e.Graphics, Me))<br />
End Sub</p>
<p> </p>
<p> </p>
<h5><span style="color: #669966;">[Control]RenderMode</span></h5>
<p>An Enumeration with all Renderers your control will support „out of the box“. This should usually include „System“, „Professional“ and „Custom“, whereas the „Custom“ mode should not be set manually</p>
<h5><span style="color: #669966;">[Control]Renderer</span></h5>
<p>The base class for all Renderers of your control. You should set it to „MustInherit“ because it usually does not render anything. It does include all methods and events that are called from your Paint method and can be overwritten by inherited classes.</p>
<p>For each item of your control that should be rendered individually (like background, borders, texts, &#8230;) you will have to include the following methods and events:</p>
<p> </p>
<p>Public Delegate Sub Render[Item]Handler( ByVal sender As Object, ByVal e As [Control]RenderEventArgs)<br />
Public Event RenderBorder As RenderBorderHandler</p>
<p>Public Overridable Sub Draw[Item]( ByVal e As [Control]RenderEventArgs)<br />
Call OnRender [Item] (e)<br />
End Sub</p>
<p>Protected Overridable Sub OnRender[Item]( ByVal e As [Control]RenderEventArgs)<br />
RaiseEvent Render[Item]( Me, e)<br />
End Sub</p>
<p> </p>
<p> </p>
<p>By doing so, you or any other developer will be able to alter the rendering behaviour by simply overriding the Draw[Item] method.</p>
<h5><span style="color: #669966;">[Control]SystemRenderer</span></h5>
<p>This class inherits from the [Control]Renderer and overrides every Draw[Item] method to implement a XP-like rendering of the control.</p>
<h5><span style="color: #669966;">[Control]ProfessionalRenderer</span></h5>
<p>This class inherits from the [Control]Renderer and overrides every Draw[Item] method to implement a Office-like rendering of the control.</p>
<h5><span style="color: #669966;">[Control]RenderEventArgs</span></h5>
<p>This class holds all the information that the renderer classes need to render the control, most noteably the following properties:</p>
<p>AffectedBounds<br />
a rectangle that defines the space where the renderer can draw into.</p>
<p>Graphics<br />
the graphics reference from the controls OnPaint method</p>
<p>[Control]<br />
a reference to the instance of the control itself</p>
<p>It is possible that you will have to implement multiple [Control]RenderEventArgs to cover all the specific needs of the rendering method of the item (e.g. a text to be drawn&#8230;)</p>
<h2>An Example</h2>
<p>I put together a simple example to show you how it can be done. I chose a simple rectangle control that has a border and a linear gradient as background.</p>
<p>It will support a system renderer that uses the new theming capacities of .net 2.0, a ProfessionalRenderer, that uses the Office style and a userdefined renderer, just to show how you can override the standard behaviour.</p>
<h4><span style="color: #669966;">The BoxControlClass</span></h4>
<p>This is the user control itself. A very simple control that displays a border and a background. Different to a regular approach, the BoxControlClass has no idea how this border and background will look like. This is the work of the Renderers.</p>
<p>The BoxControl has two items, the border and the background:</p>
<h4><span style="color: #669966;">The BoxControlRenderMode Enumeration</span></h4>
<p>This enumeration holds all the standard renderers that are provided with this control. Currently this is System and Professional. The Custom value is needed only for referring to a derived renderer class.</p>
<h4><span style="color: #669966;">The BoxControlRenderer Class</span></h4>
<p>This class is declared as MustInherit and is the base class for all renderers that can be attached to the BoxControl class. It implements the drawing methods for any part and its events. Here is an example of the background part declarations:</p>
<p> </p>
<p>Public Delegate Sub RenderBackgroundHandler(ByVal sender As Object, ByVal e As BoxControlRenderEventArgs)<br />
Public Event RenderBackground As RenderBackgroundHandler</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; the entry point for the BoxControl painting calls.<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;param name=&#8221;e&#8221;&gt;an EventArgs class that holds all the information<br />
&#8221;&#8217; needed for drawing the class&lt;/param&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Overridable Sub DrawBackground(ByVal e As BoxControlRenderEventArgs)<br />
Call OnRenderBackground(e)<br />
End Sub</p>
<p>Protected Overridable Sub OnRenderBackground(ByVal e As BoxControlRenderEventArgs)<br />
RaiseEvent RenderBackground(Me, e)<br />
End Sub</p>
<p> </p>
<p> </p>
<h4><span style="color: #669966;">The BoxControlSystemRenderer Class</span></h4>
<p>This is the derived class of the standard renderer that provides system rendering services (it draws with the XP theming info). As you see, I did not overwrite the OnRenderBorder method because this renderer will not use any borders</p>
<p>Imports System.Windows.Forms.VisualStyles</p>
<p>Public Class BoxControlSystemRenderer<br />
Inherits BoxControlRenderer</p>
<p>Private renderer As VisualStyleRenderer = Nothing<br />
Private element As VisualStyleElement</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; overriding this method to draw a custom background.<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;param name=&#8221;e&#8221;&gt;&lt;/param&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Protected Overrides Sub OnRenderBackground(ByVal e As BoxControlRenderEventArgs)<br />
MyBase.OnRenderBackground(e)</p>
<p>element = VisualStyleElement.Tab.Pane.Normal</p>
<p>If Application.RenderWithVisualStyles AndAlso _<br />
VisualStyleRenderer.IsElementDefined(element) Then<br />
renderer = New VisualStyleRenderer(element)<br />
renderer.DrawBackground(e.Graphics, e.AffectedBounds)<br />
Else<br />
e.Graphics.FillRectangle(System.Drawing.SystemBrushes.Window, e.AffectedBounds)<br />
End If</p>
<p>End Sub<br />
End Class</p>
<p> </p>
<h4>The BoxControlProfessionalRenderer Class</h4>
<p>This is the derived class of the standard renderer that provides professional rendering services (it tries to immitate the current MS Office styling). This class overrides both rendering methods to draw a custom background and a custom border</p>
<p>Imports System.Drawing<br />
Imports System.Drawing.Drawing2D</p>
<p>Public Class BoxControlProfessionalRenderer<br />
Inherits BoxControlRenderer</p>
<p>Private rect As Rectangle<br />
Private bgBrush As LinearGradientBrush<br />
Private linePen As Pen</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; overriding the background rendering to draw a gradient filled rectangle<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;param name=&#8221;e&#8221;&gt;&lt;/param&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Protected Overrides Sub OnRenderBackground(ByVal e As BoxControlRenderEventArgs)<br />
MyBase.OnRenderBackground(e)</p>
<p>rect = e.AffectedBounds<br />
rect.Inflate(-1, -1)<br />
bgBrush = New LinearGradientBrush(rect, SystemColors.GradientInactiveCaption, SystemColors.InactiveCaption, LinearGradientMode.Vertical)<br />
e.Graphics.FillRectangle(bgBrush, rect)</p>
<p>bgBrush.Dispose()<br />
End Sub</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; overriding the border rendering to draw a simple line<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;param name=&#8221;e&#8221;&gt;&lt;/param&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Protected Overrides Sub OnRenderBorder(ByVal e As BoxControlRenderEventArgs)<br />
MyBase.OnRenderBorder(e)</p>
<p>rect = e.AffectedBounds<br />
rect.Inflate(-1, -1)<br />
linePen = New Pen(SystemColors.ActiveCaption)<br />
linePen.Width = 1<br />
e.Graphics.DrawRectangle(linePen, rect)</p>
<p>linePen.Dispose()<br />
End Sub<br />
End Class</p>
<p> </p>
<p> </p>
<h4>The BoxControlUserRenderer</h4>
<p>This class also inherits from the baser BoxControlRenderer. But since it’s not included as a RenderMode you can only use it with setting the BoxControl’s Renderer property. This class hase some special features that allows you to set the background colors, border widths and so on at runtime to alter it’s rendering behavior.</p>
<p>Imports System.Drawing<br />
Imports System.Drawing.Drawing2D</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; this class provides a special rendering to the BoxControl<br />
&#8221;&#8217; where you can set colors and properties at runtime<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Class BoxControlUserRenderer<br />
Inherits BoxControlRenderer</p>
<p>Private bgBrush As Brush = SystemBrushes.ControlLight<br />
Private linePen As Pen = SystemPens.ControlLightLight<br />
Private rndCorners As Corner = Corner.All<br />
Private radius As Integer = 5<br />
Private rect As Rectangle</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; the background brush with which the renderer draws the background part<br />
&#8221;&#8217; you can set this property to a simple Brush or a gradient brush<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;value&gt;&lt;/value&gt;<br />
&#8221;&#8217; &lt;returns&gt;&lt;/returns&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Property BackgroundBrush() As Brush<br />
Get<br />
Return bgBrush<br />
End Get<br />
Set(ByVal value As Brush)<br />
bgBrush = value<br />
End Set<br />
End Property</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; the pen with which the border around the control is drawn.<br />
&#8221;&#8217; Using a pen will allow you to set the border&#8217;s width, dotted lines<br />
&#8221;&#8217; and other properties<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;value&gt;&lt;/value&gt;<br />
&#8221;&#8217; &lt;returns&gt;&lt;/returns&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Property BorderPen() As Pen<br />
Get<br />
Return linePen<br />
End Get<br />
Set(ByVal value As Pen)<br />
linePen = value<br />
End Set<br />
End Property</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; this property allows you to specify all or some corners that will be<br />
&#8221;&#8217; drawn with a rounded effect<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;value&gt;&lt;/value&gt;<br />
&#8221;&#8217; &lt;returns&gt;&lt;/returns&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Property RoundedCorners() As Corner<br />
Get<br />
Return rndCorners<br />
End Get<br />
Set(ByVal value As Corner)<br />
rndCorners = value<br />
End Set<br />
End Property</p>
<p>&#8221;&#8217; &lt;summary&gt;<br />
&#8221;&#8217; the corner radius (in points) of the rounded edges.<br />
&#8221;&#8217; &lt;/summary&gt;<br />
&#8221;&#8217; &lt;value&gt;&lt;/value&gt;<br />
&#8221;&#8217; &lt;returns&gt;&lt;/returns&gt;<br />
&#8221;&#8217; &lt;remarks&gt;&lt;/remarks&gt;<br />
Public Property CornerRadius() As Integer<br />
Get<br />
Return radius<br />
End Get<br />
Set(ByVal value As Integer)<br />
radius = value<br />
End Set<br />
End Property</p>
<p>Protected Overrides Sub OnRenderBackground(ByVal e As BoxControlRenderEventArgs)<br />
MyBase.OnRenderBackground(e)<br />
rect = e.AffectedBounds<br />
rect.Inflate(linePen.Width * (-1), linePen.Width * (-1))<br />
e.Graphics.FillPath(bgBrush, DrawingHelperClass.RoundedRect(rect, radius, rndCorners))</p>
<p>End Sub</p>
<p>Protected Overrides Sub OnRenderBorder(ByVal e As BoxControlRenderEventArgs)<br />
MyBase.OnRenderBorder(e)</p>
<p>rect = e.AffectedBounds<br />
rect.Inflate(linePen.Width * (-1), linePen.Width * (-1))<br />
e.Graphics.DrawPath(linePen, DrawingHelperClass.RoundedRect(rect, radius, rndCorners))<br />
End Sub<br />
End Class</p>
<p> </p>
<p> </p>
<h4><span style="color: #669966;">BoxControlRenderEventArgs</span></h4>
<p>This class holds all the info needed for drawing the border and the background in the renderer classes. The EventArgs are pushed to the renderer in the OnPaint method of the BoxControl class</p>
<p> </p>
<p>Public Class BoxControlRenderEventArgs<br />
Inherits System.EventArgs</p>
<p>Private _affectedBounds As Rectangle<br />
Private _graphics As Graphics<br />
Private _box As BoxControl</p>
<p>Public Sub New(ByVal g As Graphics, ByVal box As BoxControl)<br />
_graphics = g<br />
_box = box<br />
End Sub</p>
<p>Public ReadOnly Property AffectedBounds() As Rectangle<br />
Get<br />
Return New Rectangle(_box.Padding.Left, _<br />
_box.Padding.Top, _<br />
_box.Width &#8211; _box.Padding.Left &#8211; _box.Padding.Right, _<br />
_box.Height &#8211; _box.Padding.Top &#8211; _box.Padding.Bottom)</p>
<p>End Get<br />
End Property</p>
<p>Public ReadOnly Property Graphics() As Graphics<br />
Get<br />
Return _graphics<br />
End Get<br />
End Property<br />
End Class</p>
<p> </p>
<p> </p>
<h2>The Test Application</h2>
<p>The Test Application allows you to apply multiple renderers to the BoxControl on the left. If you choose the Userdefined Renderer, you will be allowed to customize the rendering of the BoxControl further. Change the colors by double-clicking on the color-fields</p>
<h2>Conclusion</h2>
<p>The Renderer-Approach is a very nice but labour-intensive way of allowing your controls to be rendered by custom code. I will certainly implement this for most of the XPCommonControls.</p>
<p>Because I don’t want to break compatibility with the current release, I’m planning to create a new library with rendered controls only.</p>
]]></content:encoded>
			<wfw:commentRss>http://code.steepvalley.net/?feed=rss2&amp;p=21</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
