<?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>Excel Programming   : VBA</title><link>http://blogs.msdn.com/gabhan_berry/archive/tags/VBA/default.aspx</link><description>Tags: VBA</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Using Custom Functions in Dynamic Ranges</title><link>http://blogs.msdn.com/gabhan_berry/archive/2008/02/19/using-custom-functions-in-dynamic-ranges.aspx</link><pubDate>Tue, 19 Feb 2008 20:33:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7798180</guid><dc:creator>Gabhan Berry</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/gabhan_berry/comments/7798180.aspx</comments><wfw:commentRss>http://blogs.msdn.com/gabhan_berry/commentrss.aspx?PostID=7798180</wfw:commentRss><description>&lt;P&gt;Named ranges are great. They enable us to assign a name to a collection of cells and use that name in code and worksheet functions. However, named ranges tend to be static. That is, they tend to represent a fixed set of cells, such as, A1:E100. But sometimes it would be useful to have the range's set of cells be dynamic. Instead of the range representing a fixed set of cells, we would like to dynamically determine which cells are included in the range based on some custom logic. &lt;/P&gt;
&lt;P&gt;Excel already lets us do this. It allows us to embed functions inside the definition of a named range and have the functions determine on-the-fly which cells are included in the range. But it's not just native Excel functions (like IF, OFFSET, etc.) that we can embed into a named range defintion. We can also embed our own, custom functions; we can write a custom function that uses our own application logic to dynamically determine at calculation time which cells are in a named range.&lt;/P&gt;
&lt;P&gt;This gives us the capability to &lt;EM&gt;point&lt;/EM&gt; the named range at different cells&amp;nbsp;without actually changing the named range's definition. &lt;/P&gt;
&lt;P&gt;In this posting, I'll talk about dynamic ranges&amp;nbsp;and&amp;nbsp;embedding custom functions into named range defintions.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Getting Started with Dynamic Ranges&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Let's take a simple example. Let's say that we have a column of numbers in the range 'Example 1'!$C$1:$C$100 and we want to find the cells in this range that are higher than some value, X = 34,999.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Using dynamic ranges, we can create a named range (called, say, Range 1) with a definition of:&lt;/P&gt;
&lt;P mce_keep="true"&gt;=GreaterThan('Example 1'!$C$1:$C$100, 34999)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7801259/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7801259/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;We also define a UDF called GreaterThan as:&lt;/P&gt;
&lt;P mce_keep="true"&gt;Public Function GreaterThan(Rng As Range, Limit As Long) As Range&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim Cell As Range&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim ResultRange As Range&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; For Each Cell In Rng&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If Cell.Value2 &amp;gt; Limit Then&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If ResultRange Is Nothing Then&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set ResultRange = Cell&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set ResultRange = Application.Union(ResultRange, Cell)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Next&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set GreaterThan = ResultRange&lt;BR&gt;End Function&lt;/P&gt;
&lt;P mce_keep="true"&gt;The UDF iterates over the source range testing&amp;nbsp;each cell. If the cell meets our criteria (in this case its value being greater than 34999)&amp;nbsp;then it is added into a temporary range object. Once the code has iterated over all the cells, the temporary range is returned to the caller. This range represents the set of cells the named range now refers to.&lt;/P&gt;
&lt;P mce_keep="true"&gt;(Note: we're not coping with any runtime errors in this code ... which we should do in a proper version).&lt;/P&gt;
&lt;P mce_keep="true"&gt;We can use the named range just like any other named range and Excel will call our UDF as and when it needs to. So, we could calculate the average of our range by using normal worksheet functions, such as:&lt;/P&gt;
&lt;P mce_keep="true"&gt;=AVERAGE(Range1)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7801430/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7801430/original.aspx"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;We can visually confirm the range that our UDF returned using the Name Manager. If we open up the Name Manager and select Range 1 and then click inside the 'Refers to:' textbox, Excel invokes our UDF and highlights the cells on the worksheet that our UDF returned. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7805404/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7805404/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Recalculating the Range&amp;nbsp;when Data Changes&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Excel knows that our dynamic range depends on $C$1:$C$100.&amp;nbsp;This is&amp;nbsp;because we pass $C$1:$C$100 to the UDF call in the named range definition.&lt;/P&gt;
&lt;P mce_keep="true"&gt;This enables Excel to properly calculate our named range during worksheet calculations. &amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;In our example, the cell $E$3 (which contains the formula =AVERAGE(Range1)) depends on Range 1 and Range 1 depends on $C$1:$C$100. Therefore, if $C$1:$C$100 changes, Excel knows that it needs to recalculate Range 1 in order to recalculate $E$3. &lt;/P&gt;
&lt;P mce_keep="true"&gt;So, if we change the value of $C$1 from 40000 to 20000 Excel knows that it needs to recalculate $E$3 and, hence, invokes our UDF.&amp;nbsp;Our UDF determines which cells Range 1 refers to and deems that&amp;nbsp;$C$1 is no longer part of Range 1 (because its value is no longer&amp;nbsp;&amp;gt; 34999); thus the value of $E$3 changes, as shown below.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG style="WIDTH: 299px; HEIGHT: 331px" height=331 src="http://blogs.msdn.com/photos/gabhan_berry/images/7804705/original.aspx" width=299 mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7804705/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;We can also confirm&amp;nbsp;that Range1 is comprised of different cells&amp;nbsp;by inspecting&amp;nbsp;Range1's address in the VBA Immediate window (this also illustrates that we can use the dynamic named range in VBA just like we can use a 'normal' named range).&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7804821/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7804821/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;A Note about Interacting with the Calc Tree&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;If our UDF didn't declare its source data range as a parameter then Excel would not be able to call it at the appropriate times during recalculation. &lt;/P&gt;
&lt;P mce_keep="true"&gt;For example, if our UDF simply iterated through $C$1:$C$100 without declaring this range as a parameter then, when $C$1:$C$100 is changed, $E$3 wouldn't be recalculated. &lt;/P&gt;
&lt;P mce_keep="true"&gt;This is because Excel would not know that $E$3 depends on $C$1:$C$100 because that dependency&amp;nbsp;would be&amp;nbsp;hidden inside the UDF.&lt;/P&gt;
&lt;P mce_keep="true"&gt;There may circumstances when we don't care about this. But it is worth remembering that Excel needs to know about any worksheet dependencies our UDF has in order for our dynamic range to interact with the calculation tree properly.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Making More Use of Dynamic Ranges&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Our GreaterThan UDF is about as basic as could be, but, it illustrates the technique. It doesn't, however, take much imagination to see how this technique could be used in more sophisticated ways. &lt;/P&gt;
&lt;P mce_keep="true"&gt;For example, inside our UDF we could make use of external data, such as our company's databases, and use the logic and/or data stored in them to determine the contents of the dynamic range in Excel. &lt;/P&gt;
&lt;P mce_keep="true"&gt;One example could be that we have a list of dates in our worksheet and we want to highlight the dates on which somebody downloaded a trial version of our product from our web site. This would&amp;nbsp;make use&amp;nbsp;of&amp;nbsp;the same technique described here, except, in the loop in our UDF, we would make a call to the database to determine whether that cell should or should not be included in the range. &lt;/P&gt;
&lt;P mce_keep="true"&gt;In other words, using UDFs in dynamic ranges enables us to incorporate external data and external&amp;nbsp;components into our range definitions.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Another use is: search. We could write a fairly sophisticated custom, search feature that is built on top of dynamic ranges and UDFs.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Concerns About Execution Speed&lt;/STRONG&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;I'm afraid I've left the bad news until the end... &lt;/P&gt;
&lt;P mce_keep="true"&gt;Implementing dynamic ranges exactly as I have described here could hand you&amp;nbsp;serious performance issues. &lt;/P&gt;
&lt;P mce_keep="true"&gt;To illustrate this, let's change the definition of Range 1 from:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;=GreaterThan('Example 1'!&lt;STRONG&gt;$C$1:$C$100&lt;/STRONG&gt;, 34999) &lt;/P&gt;
&lt;P mce_keep="true"&gt;to:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;=GreaterThan('Example 1'!&lt;STRONG&gt;$C:$C&lt;/STRONG&gt;, 34999).&lt;/P&gt;
&lt;P mce_keep="true"&gt;Now, we are checking for cells greater than 34999 in the &lt;EM&gt;entire&lt;/EM&gt; C column. In Excel 2007, that's 1,048,576 cells. On my PC (which is a 2.66 GHz&amp;nbsp;dual core with 3GB RAM - not that dual core helps here anyway), calculating the range &lt;EM&gt;once&lt;/EM&gt; takes 3 seconds. If we referenced Range 1 in only a handful of places in our workbook or VBA, our workbook would become fairly unusable fairly quickly.&lt;/P&gt;
&lt;P mce_keep="true"&gt;It would be interesting to see if implementing our UDF in an XLL would improve the speed substantially -&amp;nbsp;(something I'll look into).&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;Also, if our UDF did fancier things (like calling into an external database) then you can just imagine what would happen when we're iterating over 1,048,576 cells ....&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;So, it's worth stating that we should exercise some common sense and some judgement when using dynamic ranges. However, if we restrict our usage to &lt;EM&gt;suitably sized&lt;/EM&gt; source ranges, dynamic ranges are a useful tool indeed (where &lt;EM&gt;suitably sized&lt;/EM&gt; is something we each have to define for ourselves).&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Named range definitions&amp;nbsp;can contain&amp;nbsp;native and custom functions;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;A custom function used&amp;nbsp;as a named range definition should return the range that it determines the named range represents;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;To interact properly with Excel's calculation tree, all worksheet dependencies (such as the source range) should be included as parameters to the custom function;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Dynamic ranges can be used to build some fairly useful and sophisticated extensions;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Speed when iterating over large ranges is not good and we should employ careful judgment when using dynamic ranges on potentially large source ranges;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;You can download the workbook I used for this post in the list of attachments below.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7798180" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/gabhan_berry/attachment/7798180.ashx" length="18917" type="application/vnd.ms-excel.sheet.macroEnabled.12" /><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/VBA/default.aspx">VBA</category></item><item><title>Creating Custom Calculated Members and Sets in OLAP PivotTables </title><link>http://blogs.msdn.com/gabhan_berry/archive/2008/02/06/creating-custom-calculated-members-and-sets-in-olap-pivottables.aspx</link><pubDate>Wed, 06 Feb 2008 22:45:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7497054</guid><dc:creator>Gabhan Berry</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/gabhan_berry/comments/7497054.aspx</comments><wfw:commentRss>http://blogs.msdn.com/gabhan_berry/commentrss.aspx?PostID=7497054</wfw:commentRss><description>&lt;P&gt;If you are using PivotTables against an OLAP data source you may find it useful to be able to create your own custom, calculated measures and sets. These calculations are client-side meaning they exist inside Excel and you don't have to change the server-side OLAP cube.&lt;/P&gt;
&lt;P&gt;Excel does not enable you to do this using the user interface, however, you can do this via the API.&lt;/P&gt;
&lt;P&gt;Allan Folting (our PivotTable expert) has published a post&amp;nbsp;showing how to do this using VBA&amp;nbsp;over in the team's blog.&lt;/P&gt;
&lt;P&gt;&lt;A class="" href="http://blogs.msdn.com/excel/archive/2008/02/05/common-questions-around-excel-2007-OLAP-PivotTables.aspx" mce_href="http://blogs.msdn.com/excel/archive/2008/02/05/common-questions-around-excel-2007-OLAP-PivotTables.aspx"&gt;Click here to read his post.&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7497054" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/VBA/default.aspx">VBA</category><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/PivotTables/default.aspx">PivotTables</category></item><item><title>MSDN Code Gallery</title><link>http://blogs.msdn.com/gabhan_berry/archive/2008/02/05/msdn-code-gallery.aspx</link><pubDate>Tue, 05 Feb 2008 23:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7473501</guid><dc:creator>Gabhan Berry</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/gabhan_berry/comments/7473501.aspx</comments><wfw:commentRss>http://blogs.msdn.com/gabhan_berry/commentrss.aspx?PostID=7473501</wfw:commentRss><description>&lt;P&gt;We have recently launched a code sharing community web site called &lt;A class="" href="http://code.msdn.microsoft.com/" mce_href="http://code.msdn.microsoft.com/"&gt;MSDN Code Gallery&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;MSDN Code Gallery hosts code snippets and entire projects that have been shared with the community. You can publish your own code or search for and download other peoples' code.&lt;/P&gt;
&lt;P&gt;There are lots of nice features on the web site.&amp;nbsp;For example, when you publish code, the site&amp;nbsp;enables issue tracking, discussions, comments&amp;nbsp;and RSS feeds pertaining to your release. &lt;/P&gt;
&lt;P&gt;The basic format is that you create resource pages. These pages each have descriptions, versioning etc. and contain releases. Each release is a file. It&amp;nbsp;can be a code snippet or documentation or any other useful file. You search the gallery using tags or using the embedded Live search. Also, the web site automatically enforces the Microsoft Public License on all the source code downloads.&lt;/P&gt;
&lt;P&gt;All in all, it seems like a great idea, so, I'll be publishing all my source code to the MSDN Code Gallery.&lt;/P&gt;
&lt;P&gt;If you're interested in publishing your own code,&amp;nbsp;you can find out&amp;nbsp;how to do it &lt;A class="" href="http://code.msdn.microsoft.com/CodeGallery" mce_href="http://code.msdn.microsoft.com/CodeGallery"&gt;here&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;As an example, the&amp;nbsp;resource page&amp;nbsp;for my post on filtering a&amp;nbsp;PivotTable&amp;nbsp;using&amp;nbsp;cell contents&amp;nbsp;has been published &lt;A class="" href="http://code.msdn.microsoft.com/CellFilterPivot" mce_href="http://code.msdn.microsoft.com/CellFilterPivot"&gt;here&lt;/A&gt;. The workbook can be downloaded&amp;nbsp;from the &lt;STRONG&gt;Releases&lt;/STRONG&gt; tab.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7473501" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/VBA/default.aspx">VBA</category></item><item><title>Using Cell Text to Filter PivotTables</title><link>http://blogs.msdn.com/gabhan_berry/archive/2008/01/31/using-cell-text-to-filter-pivottables.aspx</link><pubDate>Fri, 01 Feb 2008 02:50:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7361955</guid><dc:creator>Gabhan Berry</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/gabhan_berry/comments/7361955.aspx</comments><wfw:commentRss>http://blogs.msdn.com/gabhan_berry/commentrss.aspx?PostID=7361955</wfw:commentRss><description>&lt;P&gt;Sometimes it would be useful to be able to use cells to select items in a PivotTable. For example,&amp;nbsp;let's say we have a PivotTable&amp;nbsp;containing a field called Region. Instead of using the filter dropdown&amp;nbsp;to select the region from a list it would be nice if we could use a cell to specify the&amp;nbsp;region.&amp;nbsp;That way,&amp;nbsp;the user could just type&amp;nbsp;a region,&amp;nbsp;such as Europe,&amp;nbsp;into a cell and the PivotTable would only show data for Europe. &lt;/P&gt;
&lt;P&gt;In this post, I'll present some VBA code that does just this.&lt;/P&gt;
&lt;P&gt;Let's take an example.&lt;/P&gt;
&lt;P&gt;We have a PivotTable based on some census data&amp;nbsp;in our workbook. &amp;nbsp;We have Occupation on rows and Education Level on columns and our measure is average age. So we are looking at the average ages of different occupations and education levels.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7376206/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7376206/original.aspx"&gt;&lt;/P&gt;
&lt;P&gt;We then want to filter this data by region. So we add the Region field to report filters. Now we can see the different values for different regions by changing the in-built filter dropdown.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7376207/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7376207/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;But let's say that, instead of using the filter dropdown, we want the PivotTable to get the region&amp;nbsp;selection&amp;nbsp;from a specific cell. In other words, we want the user to be able to type Europe into a cell and the PivotTable updates to show the value for Europe, just as if the user had used the filter dropdown to select Europe.&lt;/P&gt;
&lt;P mce_keep="true"&gt;To do this, we need to do two things:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Detect when the user has entered a value into the cell;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Update the Region PivotField object with the value of the cell;&lt;/DIV&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P mce_keep="true"&gt;For the sake of clarity, let's assign a name to the cell where the user will enter the new selection for the field (i.e. let's make the cell a named range). Since we're changing the Region field, let's give the cell a name of RegionFilterRange.&lt;/P&gt;
&lt;P mce_keep="true"&gt;To detect when RegionFilterRange has changed, we handle the Workbook.SheetChange event. This event&amp;nbsp;passes in (as a parameter) a Range object&amp;nbsp;which represents the changed range. If this range intersects with the RegionFilterRange then we know that RegionFilterRange has changed.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face="Courier new"&gt;Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If Not Intersect(Target, Application.Range(RegionRangeName)) _&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Is Nothing Then&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; UpdatePivotFieldFromRange _&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; RegionRangeName, PivotFieldName, PivotTableName&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; End If&lt;/FONT&gt;&lt;FONT face="Courier new"&gt;&lt;BR&gt;End Sub&amp;nbsp;&lt;/FONT&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;PivotFieldName is the name of the the field we are updating (in this case Region) and PivotTableName is the name of the PivotTable we are changing.&lt;/P&gt;
&lt;P mce_keep="true"&gt;The code for updating the PivotField object is implemented in the function UpdatePivotFieldFromRange. I've made the code generic&amp;nbsp;so that it can update any field in any PivotTable (in the active workbook) to&amp;nbsp;the value of a specified range&amp;nbsp;(these three things are passed in as parameters).&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face="Courier new"&gt;Public Sub UpdatePivotFieldFromRange(RangeName As String, FieldName As String, _&lt;BR&gt;PivotTableName As String)&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim rng As Range&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set rng = Application.Range(RangeName)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim pt As PivotTable&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim Sheet As Worksheet&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; For Each Sheet In Application.ActiveWorkbook.Worksheets&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; On Error Resume Next&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set pt = Sheet.PivotTables(PivotTableName)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Next&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If pt Is Nothing Then GoTo Ex&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; On Error GoTo Ex&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pt.ManualUpdate = True&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Application.EnableEvents = False&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Application.ScreenUpdating = False&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim Field As PivotField&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set Field = pt.PivotFields(FieldName)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Field.ClearAllFilters&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Field.EnableItemSelection = False&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SelectPivotItem Field, rng.Text&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pt.RefreshTable&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;Ex:&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; pt.ManualUpdate = False&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Application.EnableEvents = True&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Application.ScreenUpdating = True&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;End Sub&lt;/FONT&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;FONT face="Courier new"&gt;Public Sub SelectPivotItem(Field As PivotField, ItemName As String)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Dim Item As PivotItem&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; For Each Item In Field.PivotItems&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Item.Visible = (Item.Caption = ItemName)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Next&lt;BR&gt;End Sub&lt;/FONT&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;UpdatePivotFieldFromRange first of all gets a reference to the required PivotTable and stores it in pt. Then it gets a reference to the required PivotField and stores that in Field. &lt;/P&gt;
&lt;P mce_keep="true"&gt;pt.ManualUpdate = True stops the PivotTable from automatically updating as we make changes. It basically means that we have to tell the PivotTable when it should update. Application.EnableEvents = False stops events like Workbook.SheetChange from firing while our code is executing. &lt;/P&gt;
&lt;P mce_keep="true"&gt;SelectPivotItem loops through all the items in the field and sets each one's Visible property to False except for the item specified by ItemName which is set to True. This ensures that only ItemName will be visible in the field.&lt;/P&gt;
&lt;P mce_keep="true"&gt;Notice that in UpdatePivotFieldFromRange we set Field.EnableItemSelection = False. This hides the dropdown filter window from the user so they can't click on the PivotTable and change the field selection using the filter dropdown list.&lt;/P&gt;
&lt;P mce_keep="true"&gt;So, our code now enables us to enter an item name in the RegionFilterRange named range and use that value to filter our PivotTable. &lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7376573/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7376573/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;It doesn't matter where&amp;nbsp;the Region field is. It could be on Report Filters, Columns or Rows.&amp;nbsp;&amp;nbsp;In the following screenshot, we have moved Region to Columns.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;IMG src="http://blogs.msdn.com/photos/gabhan_berry/images/7376718/original.aspx" mce_src="http://blogs.msdn.com/photos/gabhan_berry/images/7376718/original.aspx"&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Summary&lt;/STRONG&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Cells can be used to filter PivotTables by programmatically setting the field selection to the value of the cell;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Use the Workbook.SheetChange event to detect changes to the cell;&lt;/DIV&gt;&lt;/LI&gt;
&lt;LI&gt;
&lt;DIV mce_keep="true"&gt;Set Application.EnableEvents = False and PivotTable.ManualUpdate = True to avoid Excel events from firing and the PivotTable automatically updating itself while your code exeutes;&lt;/DIV&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P mce_keep="true"&gt;I have only talked about PivotTables that are based on data inside Excel. This code won't work for OLAP PivotTables. I&amp;nbsp;might post a OLAP version in a later&amp;nbsp;article if there is interest.&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Download the Source Code&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;An example Excel 2007 workbook containing the VBA, data and PivotTable&amp;nbsp;for this post has been published to the MSDN Code Gallery and can be downloaded by clicking on the link below (go to the &lt;STRONG&gt;Releases&lt;/STRONG&gt; tab to download the workbook).&amp;nbsp;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A class="" href="http://code.msdn.microsoft.com/CellFilterPivot" mce_href="http://code.msdn.microsoft.com/CellFilterPivot"&gt;Click here to download&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7361955" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/VBA/default.aspx">VBA</category><category domain="http://blogs.msdn.com/gabhan_berry/archive/tags/PivotTables/default.aspx">PivotTables</category></item></channel></rss>