frice's WebLog

  • Excel's Worksheets and Sheets Collection - What's the Difference?

    Among the top four objects most searched for on the Microsoft Developer Network by Excel programmers are the Sheets collection and the Worksheets collection (the other two are the Range object and the Application object). As an aside, I've written new articles on programming the Range and Application objects which will be published on the Office Developer Center in January 2008.

    For new Excel programmers, there might be some confusion as to the difference between the Sheets and Worksheets collections. The Worksheets collection contains the items you typically think of on an Excel worksheet: rows, columns, cells, and formulas. The Sheets collection, on the other hand, consist of not only a collection of worksheets but also other types of sheets to include Chart sheets, Excel 4.0 macro sheets (also known as XLM files) and Excel 5.0 dialog sheets (allows you to create custom dialog boxes). Chart sheets are charts that take up an entire worksheet, but not charts that are inserted as part of a worksheet. The Excel 4 and Excel 5 sheets are legacy items used to maintain backwards compatibility and ease the transition from older versions of Excel to new. And just to further muddy the waters, there is also a Charts collection that is made up of chart sheets.

    The Count property of the Worksheets collection contains the number of worksheets in a workbook. The Count property of the Sheets collection contains the number of all sheets in a workbook to include chart sheets and worksheets. For example, you can add a specific number of worksheets to a workbook with the following:

    Do While Worksheets.Count < 5
       ThisWorkbook.Sheets.Add
    Loop

    The worksheets you add may then become either a chart sheet or left as a worksheet, at which time, they become part of the Charts or Worksheets collection, respectively, or collectively become members of the Sheets collection. In the following example, you change the name of the last sheet in a workbook:

    Dim wrkSheetName As String
    wrkSheetName = "Projected Sales Chart"
    Sheets(Sheets.Count).Name = wrkSheetName

    Note that because you are using the Sheets collection, the last sheet in this workbook could be either a worksheet or a chart sheet. Given the name, it is likely a chart sheet.

    As you might expect, the Sheets collection contains more methods than the Worksheets collection since it is home to more types of sheets. However, in both collections, there are a variety of methods to do such things as add, delete, copy, and move a sheet. There is ample documentation on these and other properties, methods, and events of the Worksheets and Sheets collections from the Excel portal on Office Developer Center on MSDN (http://msdn.microsoft.com/office).

  • Check out these new articles on MSDN

    The article Calling Excel 2007 Custom Wizards from the Office Fluent Ribbon by Using VBA (http://msdn2.microsoft.com/en-us/library/bb927654.aspx) demonstrates how to create a custom wizard in  Excel 2007 using VBA and then modify the Ribbon to call the wizard.

    Albert Raiani does a great job in explaining how to trigger custom code when you drag data from an external source onto a Excel 2007 worksheet in his newly released article Adding Drag-and-Drop Functionality using the .NET Framework and Visual Studio 2005 Tools for Office Second Edition (http://msdn2.microsoft.com/en-us/library/bb840032.aspx). Lots of examples also.

    Also, take a look at the six-part Office Talk columns titled Bringing Improvements to the Excel 2007 Table (Part 1 through 6) (http://msdn2.microsoft.com/en-us/library/bb693324(office.11).aspx) on enhancements to data tables in Excel 2007 and how working with tables is much easier than in previous versions.

    Enjoy!

  • Cool translation feature in Microsoft Office

    One of the coolest features in Office that I think many people (well, at least me) overlook is the translation capability. You can type in a word and get a translation immediately in any language you select. I'm currently trying to teach myself Spanish and find this feature really useful.

    http://frice.officeisp.net/Miscellaneous%20pictures/OfficeTranslationFeature.gif

    In most Office 2007 applications, you can find the translation feature on the Research pane in the Proofing group on the Review tab. In Outlook, right-click anywhere in the message body of an e-mail, and then click Translate on the shortcut menu.

  • Using Code Snippets in Visual Studio 2005 is Incredible

    Visual Studio 2005 code snippets are a neat way to package pieces of code that you want to keep close at hand. These can be code samples that you've created or samples that you find during searches. And creating them is pretty easy with some of the free editors that are available. Such as:

    Visual Basic 2005: http://searchvb.techtarget.com/tip/0,289483,sid8_gci1173726,00.html

    C#: http://blogs.msdn.com/gusperez/articles/93681.aspx

    I recently created and posted over 100 code snippets on the Microsoft Office Developer Center (http:\msdn2.microsoft.com\Office) to customize the Office Fluent Ribbon in Visual Basic and C# for Excel, PowerPoint, and Word using both editors and it was relatively painless to create them. You can find a link to the Ribbon code snippets and some of the Ribbon customization how-to videos I'm doing on Erika Ehrli's blog at:

    http://blogs.msdn.com/erikaehrli/archive/2007/03/26/officeFluentUI_5F00_RibbonCodeSnippetsAndOfficeVisualHowToSeries.aspx

    Since a lot of the header information of the Ribbon code snippets was the same, I found it easier to create a couple of the basic Ribbon customization snippets using the editors and copy and modify them in NotePad for the majority of the other samples.

    Up until I started using code snippets, when I ran across pieces of code that I thought I might use at some later time, I keep them in a folder on my hard drive as a text file. Then in the heat of battle, I'd usually forget that I had the samples and when I did, I had to stop what I was doing in Visual Studio and search through them to find the right one (assuming I had given them a descriptive name).

    Code snippets allow you to group similar samples together in a series of folders and then make those folders available right in Visual Studio without having to break your workflow. Just create a link to the folder(s) by clicking Code Snippet Manager on the Tools menu. Then to use, place the curosr in the desired location in the code window, right-click, click Insert Snippet, and the code is dropped into the code. Pretty sweet.

    You can find more information about using code snippets in Visual Studio by searching in MSDN and also by searching the Internet.   

  • New Visual How-to content on the Microsoft Office Developer Center

    Just a quick note to say that there is new developer content on the Office Developer Center (http://msdn2.microsoft.com/en-us/office/default.aspx). These include over one hundred Ribbon code snippets that can be dropped into Visual Studio solutions. About half have been written in Visual Basic .NET and the other half werer written in C#. There are samples that target Excel, PowerPoint, and Word so check them out. We are also creating a ton of how-to videos on the Office Developer Center to include videos on the Ribbon by your truly, Open XML Format files by Ken Getz, and on Content Controls by Erika Ehrli Cabral. New video how-to are coming out almost every day so you should check the site frequently.
  • Making Sense of Your Data in Excel 2007 - AutoFilters

    Sorting and filtering data is one of the most common operations that users perform in Excel. There have been a number of improvements in sort and filtering functionality in Excel 2007 in the areas of AutoFilters, sorting, and PivotTables. In this blog, I'll discuss AutoFilters and sorting both from the UI and programmatically. I'll save PivotTables for other blogs.

    Among the improvements and additions in AutoFiltering are:

    • Multi-select that lets you select any number of items in your filter conditions,
    • The ability to sort and filter by color,
    • An increase in the number of items in the AutoFilter (10,000 as opposed to 1,000 in Excel 2003),
    • A "quick filter" feature that enables datatype-specific filtering,
    • The addition of data grouping to data AutoFilters,
    • The ability to re-apply a set of filters with a single click of the button.

    First, auto filter functionality is now easier to find as it is part of the Sort & Filter drop-down on the Home tab which is the first tab you see when you open a workbook (see Figure 1). The command was available from the Filter option on the Data menu in Excel 2003. You'll also notice that it is just called Filter now.

    Figure 1. The Filter (autofilter) option on the Home tab

    The sort options remain at the top of the drop-down but the text has been updated to reflect the type of data being sorted (sort oldest to newest for dates, sort smallest to largest for numbers, and sort A to Z for text); see Figures 2 through 4, respectively.

    Figure 2. Sort options for dates

    Figure 3. Sorts options for numbers

    Figure 4. Sort options for text

    In addition to be able to sort on datatype, you can also sort by color, either font color or background color (see Figure 5).

    Figure 5. Sort by colors options

    You can sort by icon set if you've set that up with conditional formatting. You can also sort by any combination such as icon set and background or font color. For example. assume that you have the range shown in Figure 2 and have set the following conditions for sorting the data (see Figure 6):

    Figure 6. Icon set and color sort option settings

    Here you are setting up a sort of the icon set and cell background color. Once you click Ok, the result is shown in Figure 7:

    Figure 7. The result of multiple sorts

    It doesn't matter how the color was added to the cells, either by setting the background/font or with conditional formatting, the result is the same.

    Improvements have also been made in regards to multi-select filtering. In previous versions of Excel, if you wanted to select multiple items, you needed to use the Custom dialog, and that limited you to two choices.  In Excel 2007, you can simply select the items you want to see included in your filter and click OK.  This is much faster, easier to discover, and supports as many items as you want to select (see Figure 8).

    Figure 8. Excel 2007 allows you to select multiple items for filtering

    Excel 2007 also makes it possible to express more individualized filtering conditions than just clicking individual items.  It does this by providing filtering options based on the type of data in your column. Say, for example, I’m looking at a record of sales for the past several days (as seen in the Date column in figure 7) and I want to see how much revenue I made last month and which sales brought in the most money.  By clicking the filter dropdown on my date column I’m presented with a large list of date filters, among which is the option to filter records to last month as shown in Figure 9.

    Figure 9. Data-specific filter options

    As you can see from the figure, Excel offers an array of date filters that make filtering by different date ranges a breeze. What makes these filters special is that they are based on the computer's system clock so the “last month” filter will always filter to the previous month when the filter is reapplied.  Setting up these types of dynamic filters were not as easy in previous versions of Excel. As you expect, there are comparible filters for text and numbers (see Figure 10).

    Figure 10. Data-specific filters also exist for text and numbers

    Another feature for date-based columns is that the filter drop-down groups dates by day/month/year rather than displaying a flat list of dates so that it’s easier to drill-down and pick a specific series of dates.  If you wanted to select all of the dates in a particular month for instance, you can do so in two mouse clicks as see in Figure 11.

    Figure 11. You can drill-down to specific dates

    In the same way that Excel 2007 improves upon sorting by color, it is also easy to filter based on cell or background color. Filter by color allows you to filter by font color as well as cell fill color.  In addition, it also recognizes conditional formats on cells including regular formatting, gradient fills, and conditional formatting icon sets.

    Figure 12. Filter by color options from the UI

    Excel 2007 also makes it a bit easier to notice when a column/table has been filtered as well as what filter is being applied.  For any column that has a filter set, Excel changes the filter drop-down icon to denote its filter state (see Figure 13). In addition, you can get more information by hovering the mouse over the icon in which case, Excel will show a tooltip that describes the filter state of the column.

    Figure 13. It is easy to see which columns are filtered and it filter type

    As in previous versions of Excel, a sort or filter is only applied at the time the sort or filter is created (or in the case of a table that is connected to an external data source, when the query is refreshed).  The reason for this is so that data does not move or “disappear” while you are editing it. Of course there will be times when a sort or filter becomes stale and needs to be refreshed, such as after you have copied and pasted a group of new records at the bottom of a table or range.  Excel 2007 makes it easy to reapply all sort and filter conditions on a table with the single click of a button on the Ribbon UI as shown in Figure 14.

    Figure 14. A sort or filter can be refreshed with a single mouse click.

    In closing, it is worth mentioning that everything I have discussed can be used without using a table. However, there are certain advantages to using sorting and filtering in conjunction with tables. Each table has its own "AutoFilter" whereas the worksheet can only have a single "AutoFilter", so if you need to filter more than one dataset on a worksheet then your only option is to use tables. Similarly, tables also remember their own sort conditions, so if you need the ability to maintain multiple sort states across a worksheet then tables will be your best choice.

    In future blogs, I'll discuss sorting in a little more detail as well as some of the other features of Excel 2007.

  • Customizing the Office 2007 Ribbon UI - Part 6

    In this and the next installment in the series of topics on customizing the Ribbon UI, we'll look at different scenarios for customizing the Ribbon at the application-level by using COM add-ins. These modifications could just as easily be applied to a specific document with document-level customizations using Office 2007 Open XML Formats files as described in Part 3 of this series.

    First, you'll create the project in Visual Studio using C#. Next, you'll create different customization XML markup files and then embed those into the project. As some of the customizations involve using bitmap icons, you'll need to include three of your favorite 16 x 16 pixel icons. Custom icons for add-ins must be 16 x 16 pixels and be either 16-color or True Color. To get started:

    First, create the Visual C# project:
    1. Start Visual Studio .NET 2005.
    2. On the File menu, click New Project.
    3. In the New Project dialog box under Project Types, expand Other Projects, click Extensibility Projects, and then double-click Shared  Addin.
    4. Type a name for the project. In this sample, type RibbonUISamplesCS.
    5. In the first screen of the Shared Add-in Wizard, click Next.
    6. In the next screen, select "Create an Add-in using Visual C#", and then click Next.
    7. In the next screen, clear all of the selections except Microsoft Word and then click Next.
    8. Type a Name and Description for the add-in, and then click Next.
    9. In the Choose Add-in Options screen, select "I would like my Add-in to load when the host application loads" and then click Next.
    10. Click Finish to complete the wizard.

    Now add a reference to Word:
    1. In the Solution Explorer, right-click References, and then click Add Reference.

    Note: If you don't see the References folder, click the Project menu and then Show All Files.
     
    2. Scroll downward on the .NET tab, press the Ctrl key, and then select Microsoft.Office.Interop.Word.
    3. On the COM tab, scroll downward, select Microsoft Office 12.0 Object Library, and then click OK.
    4. Next add the following namespace references to the project if they don't already exist. Do this just below the namespace line:

    using System;
    using Extensibility;
    using System.Runtime.InteropServices;
    using Microsoft.Office.Core;
    using Microsoft.Office.Interop;
    using System.Drawing;
    using System.Windows.Forms;

    Implement the IRibbonExtensibility interface.
    1. In the Solution Explorer, right-click Connect.cs, and click View Code.
    2. At the end of the public class Connect statement, add a comma, and then type IRibbonExtensibility.

    Tip: You can use Microsoft IntelliSense to insert interface methods for you. For example, at the end of the public class Connect : statement, type IRibbonExtensibility, right-click, point to Implement Interface, and then click Implement Interface Explicitly. This adds a stub for the only IRibbonExtensibility interface member: GetCustomUI. The implemented method looks like this:

    string IRibbonExtensibility.GetCustomUI(string RibbonID)
    {
    }

    3. Insert the following statement into the GetCustomUI method, overwriting the existing code:

    return resource.GetString("customui-1.xml");

    4. Above the GetCustomUI method, add this statement that gives you access to the XML markup files which you'll add later:

    private ResourceManager resource = new ResourceManager();

    5. Add the callback methods that will be used in the different customization files:

    #region callbacks-1
           
    public stdole.IPictureDisp ButtonImage(IRibbonControl control)
    {
       return resource.GetImage("Icon2.bmp");
    }

    public void ButtonAction(IRibbonControl control)
    {
       Random r = new Random();
       string s = r.Next(100000, 200000).ToString();

       Microsoft.Office.Interop.Word.Application wordApp = (Microsoft.Office.Interop.Word.Application)(applicationObject);
       wordApp.Selection.InsertAfter("\nContoso Case ID " + s);
    }

    #endregion callbacks-1

    #region callbacks-2

    private Boolean randomize = false;
    private IRibbonUI myRibbon;

    public void ribbonLoaded(IRibbonUI ribbon)
    {
       myRibbon = ribbon;
    }

    public stdole.IPictureDisp getSButton(IRibbonControl control)
    {
       return resource.GetImage("Icon3.bmp");
    }

    public int bankTellers_getItemCount(IRibbonControl control)
    {
       return 6;
    }

    public stdole.IPictureDisp bankTellers_getItemImage(IRibbonControl control, int index)
    {
       Random r = new Random();

       if (!randomize)
       {
          return resource.GetImage(index + ".bmp");
       }
       else
       {
          return resource.GetImage(r.Next(0, 7).ToString() + ".bmp");
       }
    }

    public void bankTellers_OnAction(IRibbonControl control, int index)
    {
       myRibbon.Invalidate();
       Microsoft.Office.Interop.Word.Application wordApp = (Microsoft.Office.Interop.Word.Application)(applicationObject);
       wordApp.Selection.InsertAfter("Officer #" + (index+1) + " ");
       //  MessageBox.Show("You just clicked on Bank Teller #" + (index + 1) + "!");
    }

    public void toggle_randomize(IRibbonControl control, bool press)
    {
       randomize = press;
       myRibbon.Invalidate();
    }

    public string getRandomizeLabel(IRibbonControl control)
    {
       if (randomize)
       {
          return ("Randomize ON");
       }
       else
       {
          return ("Randomize OFF");
       }
    }

    #endregion callbacks-2

    #region callbacks-3
    public stdole.IPictureDisp dinoImage(IRibbonControl control)
    {
       return resource.GetImage("Icon1.bmp");
    }

    public stdole.IPictureDisp OnLoadImage(string image)
    {
       return resource.GetImage(image);
    }

    #endregion callbacks-3

    Now, we'll start creating different customization files, embedding them as resources in the project, and then observing how they impact the Ribbon UI:

    1. In a text editor, add the following XML markup:

    <?xml version="1.0" encoding="utf-8" ?>
    <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
      <ribbon>
        <tabs>
          <tab idMso="TabInsert">
            <group id="MyContosoGroup" label="Contoso!" insertAfterMso="GroupHeaderFooter">
              <button id="CInsertCaseID"
                     size="large"
                      label="Case ID Number"
                      screentip="Insert Contoso Case ID Number."
                      onAction="ButtonAction"
                      getImage="ButtonImage" />
            <!-- onAction, getImage callbacks -->
          </group>
          </tab>
        </tabs>
      </ribbon>
    </customUI>

    2. Close and save the file as customUI-1.xml.
    3. In the Solution Explorer in the project, right-click RibbonUISamplesCS, point to Add, and then click Existing Item.
    4. Navigate to the customUI-1.xml file you created, select the file, and then click Add.

    For each of the customization files you create, you will repeat these steps. After adding each file and before building and installing the project, you'll need to ensure that the GetCustomUI method points to the correct file. So in this instance, the statement in the GetCustomUI method will read:

    return resource.GetString("customui-1.xml");

    And finally, use the same procedures to add each of the three 16 x 16 bitmaps as Icon1.bmp. Icon2.bmp, and Icon3.bmp, respectively.

    Compile both the add-in and its setup project. Before beginning, make sure that Word is closed.
    1. In the Project menu, click Build Solution. You will see a message when the build is complete in the system tray in the lower left corner of the window.
    2. In the Solution Explorer, right-click RibbonSamplesCSSetup and click Build.
    3. Right-click RibbonSamplesCSSetup and click Install. This launches the RibbonSamplesCSSetup Setup Wizard screen.
    4. Click Next on all of the screens and then Close on the final screen.
    5. Start Word. You should see the "My Tab" tab to the right of the other tabs.

    If you have problems with any of this, recheck that the procedures in the project match those in the steps or go back to part 4 in this series of articles for additional troubleshooting steps. 

  • Customizing the Office 2007 Ribbon UI - Part 5

    In the previous blog, I created a COM add-in in managed C# code that customized the Ribbon UI regardless of which document was open. In this topic, I use the same customization XML and create the add-in in Visual Basic 6.0. The existing Ribbon UI in Word 2007 is modified by adding a custom tab, custom group, and button. When you click the button, a company name is inserted into the document. To get started, follow these steps:

    1. Start Microsoft Visual Basic 6.0 and select Addin as the project type. This will add a designer class to the project (Connect) and a form (frmAddin).
    2. In the Project Explorer window, open the Designer window by right-clicking Connect and then select View Object. Select Microsoft Word from the Application drop-down list.
    3. In the Initial Load Behavior drop-down list, select Startup.
    4. In the Project Explorer, right-click MyAdd and in the Property window change the name of the add-in to RibbonSampleVB.
    5. Remove frmAddin from the project.
    6. From the Project window, right-click the Connect item and select view code.
    7. Remove all of the code in the designer's code window. This code works for Visual Basic add-ins but not Microsoft Office add-ins.
    8. Add the following statement to the OnConnection method to obtain a reference to Word when the add-in loads:

       Set oWD = Application

    9. This step is optional however if you want to be notified that your add-in is actually loading when you start Word, you can add the following statement in the OnConnection procedure. Once you're satisfied that the add-is being loaded, you can remove the line and rebuild the project:

       MsgBox "My Addin started in " & Application.Name

    10. Next, at the top of the code window, add the following statements to set aside memory for the application object we added earlier and to create a reference to the Ribbon UI interface:

       Dim oWD As Object
      
       Implements IRibbonExtensibility

    11. Next, you'll implement the IRibbonExtensibilty interface's only member: GetCustomUI

       Public Function IRibbonExtensibility_GetCustomUI(ByVal RibbonID As String) As String
          IRibbonExtensibility_GetCustomUI = GetRibbonXML()
       End Function

    This procedure calls the GetRibbonXML method that, as it's name implies, returns the customization XML to the GetCustomUI method which then gives it to the Ribbon UI to implement when the add-in loads.

    12. Add the GetRibbonXML function. In this instance, the customization code is stored in a string variable that is returned to the GetCustomUI method:

       Public Function GetRibbonXML() As String
       Dim sRibbonXML As String

        sRibbonXML = "<customUI xmlns=""http://schemas.microsoft.com/office/2006/01/customui"" >" & _
                    "<ribbon>" & _
                    "<tabs>" & _
                    "<tab id=""CustomTab"" label=""My Tab"">" & _
                    "<group id=""SampleGroup"" label=""Sample Group"">" & _
                    "<button id=""Button"" label=""Insert Company Name"" size=""large"" onAction=""InsertCompanyName"" />" & _
                    "</group >" & _
                    "</tab>" & _
                    "</tabs>" & _
                    "</ribbon>" & _
                    "</customUI>"
      
       GetRibbonXML = sRibbonXML
      
       End Function
     
    13. Now, add the procedure that gets called when you click the button in the custom tab:

    Public Sub InsertCompanyName(ByVal control As IRibbonControl)
       ' Inserts the specified text at the beginning of a range or selection.
       Dim MyText As String
       Dim MyRange As Object
       Set MyRange = oWD.ActiveDocument.Range
       MyText = "Microsoft Corporation"
       ' Selection Example:
       'Selection.InsertBefore (MyText)
       ' Range Example: Inserts text at the beginning
       ' of the active document.
       MyRange.InsertBefore (MyText)
    End Sub

    14. To make sure the code compiles without error, on the Run menu, click Start with Full Compile.
    15. Once the code compiles without error, save the project and create the RibbonSampleVB.dll by clicking the File menu and then clicking Make RibbonSampleVB.dll. The designer will register the add-in for you.
    16. Start Word. You should see the "My Tab" tab to the right of the other tabs.
    17. Click on the tab and then click the Insert Company Name button. The company name is inserted into the document.

    If you have trouble loading the add-in or if the button doesn't work, you may need to do one of the following:

    1. Go to the Trust Center to enable macros. Click the Microsoft Office Button (this is the round button in the upper left of the screen).
    2. Click Trust Center, click Macro Settings, and then select the "Disable all macros with notification" and the "Trust access to the VBA project object model" options.
    3. Close and reopen the document.

    If you don’t see the My Tab tab when you start Word, you may need to add an entry to the registry. To do this, perform the following steps:

    Caution: The next few steps contain information about modifying the registry. Before you modify the registry, be sure to back it up and make sure that you understand how to restore the registry if a problem occurs. For information about how to back up, restore, and edit the registry, search for the following article in the Microsoft Knowledge Base: 256986 Description of the Microsoft Windows Registry.

    1. On the desktop click Start, click Run, and type regedit.
    2. From the Registry tab, navigate to the following registry key for the add-in:

    HKCU\Software\Microsoft\Office\Word\AddIns\RibbonXSampleVB.Connect

    Note: If the RibbonXSampleVB.Connect key does not exist, you can create it. To do so, right-click the Addins folder, point to New, and then click Key. Name the key RibbonXSampleVB.Connect. Add a LoadBehavior DWord and set its value to 3.

    And that's all there is to creating a COM Add-in to customize the Ribbon UI. In the next blog in this series, we'll look at additional properties of the Ribbon UI and XML markup you use to further customize the Ribbon UI.


     

  • Customizing the Office 2007 Ribbon UI - Part 4

    In this installment in the series on customizing the Ribbon UI, we'll look at adding application-level customization. In the previous blog, we detailed the steps to create document-level Ribbon by modifying an Open XML Formats macro-enabled file in Word 2007. In this blog, we will create application-level customizations using a managed COM add-in which we'll create in Microsoft Visual Studio 2005 using C#. For consistency, we'll use the same customization that we used in the previous blog; namely adding a custom tab, a custom group, and button that will insert a company name into a Word 2007 document at the beginning of the document. This is the procedure:

    1. In a text editor, add the following XML markup:

    <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
      <ribbon>
        <tabs>
          <tab id="CustomTab" label="My Tab">
            <group id="SampleGroup" label="Sample Group">
              <button id="Button" label="Insert Company Name" size="large" onAction="InsertCompanyName" />
            </group >
          </tab>
        </tabs>
      </ribbon>
    </customUI>

    2. Close and save the file as customUI.xml.

    Now create the Visual C# project to modify the Ribbon UI:
    1. Start Visual Studio .NET 2005.
    2. On the File menu, click New Project.
    3. In the New Project dialog box under Project Types, expand Other Projects, click Extensibility Projects, and then double-click Shared Addin.
    4. Type a name for the project. In this sample, type RibbonXSampleCS.
    5. In the first screen of the Shared Add-in Wizard, click Next.
    6. In the next screen, select "Create an Add-in using Visual C#", and then click Next.
    7. In the next screen, clear all of the selections except Microsoft Word and then click Next.
    8. Type a Name and Description for the add-in, and then click Next.
    9. In the Choose Add-in Options screen, select "I would like my Add-in to load when the host application loads" and then click Next.
    10. Click Finish to complete the wizard.

    Now add a reference to Word:
    1. In the Solution Explorer, right-click References, and then click Add Reference.

    Note: If you don't see the References folder, click the Project menu and then Show All Files.
     
    2. Scroll downward on the .NET tab, press the Ctrl key, and then select Microsoft.Office.Interop.Word.
    3. On the COM tab, scroll downward, select Microsoft Office 12.0 Object Library, and then click OK.
    4. Next add the following namespace references to the project if they don't already exist. Do this just below the namespace line:

    using System.Reflection;
    using Microsoft.Office.Core;
    using System.IO;
    using System.Xml;
    using Extensibility;
    using System.Runtime.InteropServices;
    using MSword = Microsoft.Office.Interop.Word;

    Add the XML customization file as an embedded resource in the project by following these steps:
    1. In the Solution Explorer, right-click RibbonXSampleCS, point to Add, and click Existing Item.
    2. Navigate to the customUI.xml file you created, select the file, and then click Add.
    3. In the Solution Explorer, right-click customUI.xml, and then select Properties.
    4. In the properties window select Build Action, and then scroll down to Embedded Resource.

    Next, to get access to its members, you need to implement the IRibbonExtensibility interface.
    1. In the Solution Explorer, right-click Connect.cs, and click View Code.
    2. Just below the Connect method, add the following declaration which creates a reference to the Word application object:

    private MSword.Application applicationObject;

    3. Add the following line to the OnConnection method. This statement creates an instance of the Application object:

    applicationObject =(MSword.Application)application;
     
    4. At the end of the public class Connect statement, add a comma, and then type IRibbonExtensibility.

    Tip: You can use Microsoft IntelliSense to insert interface methods for you. For example, at the end of the public class Connect : statement, type IRibbonExtensibility, right-click, point to Implement Interface, and then click Implement Interface Explicitly. This adds a stub for the only IRibbonExtensibility interface member: GetCustomUI. The implemented method looks like this:

    string IRibbonExtensibility.GetCustomUI(string RibbonID)
    {
    }

    5. Insert the following statement into the GetCustomUI method, overwriting the existing code:
                return GetResource("customUI.xml");

    6. Insert the following method below the GetCustommUI method:

            private string GetResource(string resourceName)
            {
                Assembly asm = Assembly.GetExecutingAssembly();
                foreach (string name in asm.GetManifestResourceNames())
                {
                    if (name.EndsWith(resourceName))
                    {
                        System.IO.TextReader tr = new System.IO.StreamReader(asm.GetManifestResourceStream(name));
                        //Debug.Assert(tr != null);
                        string resource = tr.ReadToEnd();

                        tr.Close();
                        return resource;
                    }
                }
                return null;
            }

    Note: The GetCustomUI method calls the GetResource method. The GetResource method sets a reference to this assembly during runtime and then loops through the embedded resource until it finds the one named "customUI.xml." It then creates an instance of the StreamReader object that reads the embedded file containing the XML markup. The procedure passes the XML back to the GetCustomUI method which returns the XML to the Ribbon. Alternately, you can also construct a string that contains the XML markup and read it directly in the GetCustomUI method.
     
    7. Following the GetResource method, add this method. This method inserts the company name into the document at the beginning of the page:

            public void InsertCompanyName(IRibbonControl control)
            {
            // Inserts the specified text at the beginning of a range.
                string MyText;
                MyText = "Microsoft Corporation";

                MSword.Document doc = applicationObject.ActiveDocument;

                //Inserts text at the beginning of the active document.
                object startPosition = 0;
                object endPosition = 0;
                MSword.Range r = (MSword.Range)doc.Range(
                       ref startPosition, ref endPosition);
                r.InsertAfter(MyText);
            }

    Compile both the add-in and its setup project. Before beginning, make sure that Word is closed.
    1. In the Project menu, click Build Solution. You will see a message when the build is complete in the system tray in the lower left corner of the window.
    2. In the Solution Explorer, right-click RibbonXSampleCSSetup and click Build.
    3. Right-click RibbonXSampleCSSetup and click Install. This launches the RibbonXSampleCSSetup Setup Wizard screen.
    4. Click Next on all of the screens and then Close on the final screen.
    5. Start Word. You should see the "My Tab" tab to the right of the other tabs.

    To test the project:
    Click the "My tab" tab and then click the "Insert Company Name" button. The company name is inserted into the document at the cursor location.

    If you don’t see the customized Ribbon UI, you may need to add an entry to the registry. To do this, perform the following steps:

    Caution: The next few steps contain information about modifying the registry. Before you modify the registry, be sure to back it up and make sure that you understand how to restore the registry if a problem occurs. For information about how to back up, restore, and edit the registry, search for the following article in the Microsoft Knowledge Base: 256986 Description of the Microsoft Windows Registry.

    1. In the Solution Explorer, right click on the setup project, RibbonXSampleCSSetup, point to View, and then click Registry.
    2. From the Registry tab, navigate to the following registry key for the add-in:

    HKCU\Software\Microsoft\Office\Word\AddIns\RibbonXSampleCS.Connect

    Note: If the RibbonXSampleCS.Connect key does not exist, you can create it. To do so, right-click the Addins folder, point to New, and then click Key. Name the key RibbonXSampleCS.Connect. Add a LoadBehavior DWord and set its value to 3.

    And that's all there is to creating a COM Add-in to customize the Ribbon UI. In the next blog in this series, we'll look at customizing the Ribbon UI by using a COM add-in created in Visual Basic.

     

     

  • Customizing the Office 2007 Ribbon UI - Part 3

    In this blog, I will walk through an example of adding a custom tab, custom group, and a button with a simple callback procedure to the Ribbon in a Word 2007 document. To get started:

    1. Create the customization file in any text editor by adding the following XML markup to the file. Save the file as customUI.xml.
    2. Add the following XML markup to the file:

    <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
      <ribbon>
        <tabs>
          <tab id="CustomTab" label="My Tab">
            <group id="SampleGroup" label="Sample Group">
              <button id="Button" label="Insert Company Name" size="large" onAction="ThisDocument.InsertCompanyName" />
            </group >
          </tab>
        </tabs>
      </ribbon>
    </customUI>


    3. Create a folder on your desktop named customUI and copy the XML customization file to the folder.
    4. Validate the XML markup with a custom UI schema.
    Note:  This step is optional. For an example of tools you can use to validate XML markup, see the XSD Schema Validator on this Web site: http://apps.gotdotnet.com/xmltools/xsdvalidator.

    5. Create a document in Word 2007 and save it with the name RibbonSample.docm.
    6. Open the Visual Basic Editor and add the following procedure to the ThisDocument code module.

    Sub InsertCompanyName(ByVal control As IRibbonControl)
       ' Inserts the specified text at the beginning of a range or selection.
       Dim MyText As String
       Dim MyRange As Object
       Set MyRange = ActiveDocument.Range
       MyText = "Microsoft Corporation"
       ' Range Example: Inserts text at the beginning
       ' of the active document
       MyRange.InsertBefore (MyText)
       ' Selection Example:
       'Selection.InsertBefore (MyText)
    End Sub

    7. Close and save the document.
    8. Add a .zip extension to the document file name and double-click to open the file.
    9. Add the customization file to the container by dragging the customUI folder from the desktop to the Zip file.
    10. Extract the .rels file to your desktop. A _rels folder containing the .rels file is copied to your desktop.
    11. Open the .rels file and add the following line between the last <Relationship> tag and the <Relationships> tag. This creates a relationship between the document file and the customization file:

    <Relationship Id="someID" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml" />

    12. Close and save the file.
    13. Add the _rels folder back to the container file by dragging it from the desktop, overwriting the existing file.
    14. Rename the document file to its original name by removing the .zip extension.
    15. Open the document and notice that the Ribbon UI now displays the My Tab tab.
    16. Click the tab and notice the Sample Group group with a button control.
    17. Click the button and the company name is inserted into the document.

    As you can see, adding your own customizations to the Ribbon UI is very easy. In the next blog, we'll look at adding additional controls and working with existing components.
     

  • Customizing the Office 2007 Ribbon UI - Part 2

    In the previous blog, I discussed reasons for the new Office Ribbon UI, ways to customize the Ribbon, parts of the Ribbon, and gave an example of an XML customization file. In this blog, I'll talk some about callback procedures that give the Ribbon's controls and components functionality.
    A callback is a way of telling one procedure, say procA, where to send messages when procA has completed a task. It's just like giving someone a job to do and also giving them a contact number where they can reach you once the job has been completed. Consider the case of the onAction callback procedure for a button. When you click the button, the callback procedure specified for the onAction event is called and executed. When the task has completed, the procedure notifies and passes control back to the Ribbon.
    In the example I gave in the previous blog, the Launcher1 button specified an onAction callback procedure named "AdditionalWidgetOptions." When you click the button, the callback procedure, which resides in your document, is called. The procedure performs whatever task it has been given, for example setting text to bold, and then notifies the Ribbon that the task has been completed and returns control back to the Ribbon.
    Now lets briefly look at sample code that supports the XML markup. This particular sample is a portion of an add-in class created as managed C# code in Visual Studio but could just as easily be created in Visual Basic, Visual C++, any of the .NET languages, or VBA. The IDTExtensibility2 implementations have been left out in order to make the example less cluttered:

    public class Connect : Object, Extensibility.IDTExtensibility2, IRibbonExtensibility
    {
       public string GetCustomUI()
       {
          StreamReader customUIReader = new System.IO.StreamReader("C:\\Visual Studio Projects\\RibbonXSampleCS\\customUI.xml");
          string customUIData = customUIReader.ReadToEnd();
          return customUIData;

       #region Ribbon callbacks

       public void ButtonOnAction(IRibbonControl control)
       {
          MessageBox.Show("Button clicked: " + control.Id);
       }

       public void ToggleButtonOnAction(IRibbonControl control, bool pressed)
       {
          if (pressed)
             MessageBox.Show("ToggleButton pressed.");
          else
             MessageBox.Show("ToggleButton un-pressed.");
       }

       public void EditBoxOnChange(IRibbonControl control, string text)
       {
          ///Do something with 'text' here.
       }

       #endregion
    }

    First, the class must implement the Extensibility.IDTExtensibility2 and IRibbonExtensibility interfaces. Anyone who has created add-ins is already familiar with implementing the IDTExtensibility2 interface. The IRibbonExtensibility interface exposes the GetCustomUI method. The GetCustomUI method is the only method defined in the IRibbonExtensibility interface. In this example, it creates an instance of the System.IO.StreamReader that reads a file containing the XML markup. The method stores the XML customization markup in a variable named customUIData. You could also construct a string containing the XML markup or open an embedded resource (a file contained in the project itself) to supply the XML markup. The sample also includes three callback procedures. The first, ButtonOnAction, receives an object representing the button pressed and displays a message showing the id of the control. The next procedure, ToggleButtonOnAction, receives the toggleButton object and a boolean indicating whether the togglebutton was pressed and then displays a message in a dialog box. The third procedure is a stub procedure that is called when the contents of an editBox control changes. An object representing the clicked control is passed in as well as the text in the editBox. You can see that the process is easily understood and easy to implement based on your needs.

    In this topic, I've discussed the basic of implementing callbacks to add functionality to the Ribbon UI. In the next topic, I will dive into customizing the Ribbon in Word by adding a button control with a simple callback procedure.

     

  • Customizing the Office 2007 Ribbon UI - Part 1

    This is the first in a series of topics focusing on the new Office 2007 user interface (UI) and Ribbon extensibility, also called RibbonX. By now, you've probably seen blogs, press releases, and other information on the virtues and benefits of the new Ribbon UI. In previous versions of Office, adding custom commands using COM add-in and command bars could be a daunting task for novice Office developers. RibbonX is a breeze. The basic structure of the Ribbon is a hierarchical model, consisting of tabs containing groups of commands and controls displayed in logical, easy-to-find groupings using familiar controls such as drop down dialog boxes, buttons, and context (right-click) menus. The Ribbon also includes rich, interactive new controls called galleries that allows you to see what a change will look like in your document before you actually commit the change. Solutions created in previous versions of Office continue to work and are added to an "Add-Ins" tab. Context menus provide rich, commands and controls relative to the section of the document you are working in.

    Note: Some of these features, such as context (right-click) menus, the mini-Toolbar, the Status Bar and live preview using galleries, are not available when customizing the Ribbon UI with add-ins. 

    Customizing the Ribbon UI is really easy. You can customize the Ribbon through combination of XML markup and any .NET language supported in Microsoft Visual Studio such as Visual Basic .NET, Visual C++, and C#. You can also customize the Ribbon UI using Microsoft Visual Basic for Applications (VBA) and Visual Basic 6.0. There are essentially two ways to customize the Ribbon, both of which at their core use XML markup: directly through a valid Office XML Open File Format file and COM add-ins either containing XML markup or reading XML from a file. Using Office XML Open File Format files allows you to add customizations by using templates (such as .xlam, .dotm files). In this topic, I'll just talk a little about the XML. I'll go into more detail on the XML and code used to create specific UIs.

    Before looking at RibbonX, I'll describe a little about some of the parts of the new UI. The Office 2007 UI is more than just the Ribbon; it is a combination of new and traditional features. For example, there is the Office Menu, available from the round Microsoft Office Button located in the upper left-corner of the application window, similar to the File menu found in previous versions of Office. This menu contains the customary New, Open, Save, and Print commands as well as additional commands like Publish, Send, and Finalize. Also in the upper left-corner of the application window is a customizable feature called the Quick Access Toolbar (QAT). The QAT exposes those controls that you typically use frequently such as Save, Undo, Repeat, and Print. The Ribbon includes enhanced versions of the familiar tool tips, called screen tips, that let you display the name and purpose of the control or command. There is a status bar of status indicators (Caps lock, Num Lock), statistics (page number, line number, column) and functions (count, average, sum). Note that the status bar is not customizable. And just as in Office 2003, there are rich, context (right-click) menus. To make it easier for users to find the options they need, they can access legacy dialog boxes in some of the groups by clicking a launcher control in the lower-right corner of some of the groups. 

    The actual Ribbon customization is done in declarative XML markup. That is, adding a line or encapsulated section to the XML markup in a customization file adds or hides a control, command, or option on the Ribbon. Attributes are used to identify, define characteristics, and add functionality. Writing XML is typically much easier than writing traditional code for many people. And because it's just text, you can write it in any text editor. Additionally, you can take advantage of the many utilities available to help you write and validate XML and associated XSDs such as those provided by Visual Studio Tools for Office.

    RibbonX uses callbacks to provide its functionality such as provide status, update properties, or perform some action. Some callbacks look and act like the event procedures you see in other languages.  You specify the callback as an attribute of an XML tag in the customization file and then define the callback in code in either the add-in, in a template, or in macro-enabled Office 2007 Open XML Formats file. For example, the XML markup for a button control can specify an onAction attribute that points to a procedure in code which is executed when the button is clicked. That procedure then calls back to the Ribbon to either provide a status or modify the Ribbon.

    The following XML markup hides a built-in tab, adds a custom tab containing a custom group containing a custom button, a togglebutton, and a combo box with options.

    <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"
    xmlns:x="http://schemas.corporatenamespace.org">
      <ribbon startFromScratch = "false" >
        <tabs>
          <tab idMso="TabCreate" visible="true" />
          <tab id="frm1Create" label="Create the purchase order" visible="true">
            <group id="frm1CustomGroup" label="A Custom Group">
              <control idMso="Copy" label="Copy Line Item" enabled="true" />
              <control idMso="Paste" label="Paste Line Item"  />
            </group>
          </tab>
          <tab id="InventoryControl" label="Inventory Control">
            <group id="x:Type" label="Widgets" >
              <button id="x:Copy" label="Copy Item" size="large" onAction="CopyItem" />
              <toggleButton id="Priority" size="large" label="Priority" getPressed="ItemPriority" />
              <comboBox id="cboStatus" label="Status" screentip="Select a status for the item" onChange="AddStatus">
                 <item id="Status1" label="In Stock" />
                 <item id="Status2" label="On Order" />
          <item id="Status3" label="Discontinued" />
       </comboBox>
       <advanced>
          <button id="Launcher1" screentip="Additional options" onAction="MyLauncher" />
       </advanced>

     </group>
          </tabs>
       </ribbon>
    </customUI>

    One of the first things you see is a <Ribbon> tag with a startFromScratch="false" attribute. Setting this attribute to True hides the built-in Ribbon controls so that you can build your own UI from scratch. The default for this attribute is False so it is included here for illustration purposes. Next, you see a built-in tab, identified as such by the idMso identifier. There is also an id identifier. The id identifier indicates a custom component. The tab contains a custom group that contains two built-in controls: Paste and Copy.

    Next comes a built-in tab containing a custom group. The group contains a number of controls. Notice that the group uses a fully qualified name prepended with the namespace alias. The group contains a button and toggleButton with various attributes defined such as label text and the size of the button. Also included is an event declaration that makes a method call when the user clicks the button. The callback method is implemented in a COM add-in or in the code part of an Open XML Formats file.

    A combo box control is added to the tab with three options. The combo box defines different attributes such as its label and a screen tip. And finally, we included a dialog box launcher control for the group that can be used to display a dialog box with additional options. 
     
    Looking at this markup, you can see how simple it is to see what's going on here and how easy it would be to add you own controls or adjust the properties of existing components. If you wanted to hide a built-in control, all you would need to do is set its visible attribute to False. In the next blog, I'll discuss callbacks procedures and how they are used, and then get into some examples of creating and modifying different commands and controls on the UI.

  • Let Access do the work of writing SQL statements for you

    One of the views associated with creating queries in the Query designer in Access is the SQL window. The SQL window displays SQL statements that are created behind the scenes when you create a query. However, the SQL window doesn't display just SQL statements. Once you see how it works with the Access Query Design window, you'll find that this window can help you in other ways. For example, you can use the SQL window to create SQL statements that you can then paste into Visual Basic for Applications (VBA) modules. Likewise, you can take SQL statements from VBA procedures and use the SQL window to troubleshoot them for you. Because the SQL windows is designed to work with SQL statements, it provides much more meaningful error messages than the generic messages that come from the VBE.

    The query design window is a great visual way to create SQL queries that you can then copy and paste into your VBA procedures. You can use the visual aspect of the query design window to easily create your SQL statement. For example, you add the tables to the design surface of the query design window, drag the fields from the table(s) to the query grid, specify any filtering and sort criteria, execute the query, perform any troubleshooting needed, open the SQL window, and there you have a working SQL statement.

    Just as a refresher, SQL statements are made up of the following components:

      |Keyword - Instructs the query to retrieve data|
             |*************Field List**************|
      SELECT Employees.[FirstName], Employees.[LastName]
      FROM Employees |**Source of the data**|
      WHERE Employees.Title = "Sales Representative" |**Filter Criteria**|
      ORDER BY Employees.LastName; (**semicolon is required**|
      |ORDERBY clause specifies the sort order|

    #Access uses parentheses to enclose the various parts of the WHERE clause but these are optional.
    #Whenever a field is specified you have the option to append the table name, separating the two with a dot.If your query refers to more than one table you must include the table name along with the field name.
    #When supplying values in a SQL statement, such as in the query criteria, the data type must be correctly defined by a "qualifier". This is done by enclosing the value between a pair of appropriate characters. For example, single (') or double quotes (") for Strings, pound sign (#) for dates, and no qualifier for numbers.
    #Square brackets are only required around field names when they contain spaces but it's good practice to include them.
    #Dates in SQL must be written in the US date format (month/day/year).
    #It is a good practice to write SQL statement in uppercase so you can distinguish SQL Statement from VBA statements. It's also good practice to write each SQL clause on a separate line.

    Once you have a working SQL statement, you can then execute it in VBA. VBA and SQL are totally two different types of languages. VBA is a programming language that you can use to get Access (and other Microsoft Office programs) to do what you want. SQL is a language used exclusively to manipulate the data and structure of a database.
    VBA has available a large number of objects, properties, methods, functions and constants to construct the sometimes complex statements used to control the program. SQL uses a limited range of "keywords" combined with information you supply, such as table names, field names, criteria, and sort order.

    There are different ways to execute SQL in VBA code. The easiest way is by using the DoCmd object's RunSQL method. Something like this:
     Dim strSQL As String
     strSQL = "... THE SQL STATEMENT GOES HERE ...”
     DoCmd.RunSQL strSQL

    The RunSQL method takes two arguments, the SQL Statement itself which must be supplied as a string (i.e. enclosed in quotes) and Use Transaction which is optional and assumes True if you omit it. When transaction processing is applied to a query, Access first performs a "dry run" of the query during which it writes all the changes to a temporary log file but does not make any permanent changes to the database. If the query finishes its task without any problems, the changes noted in the log file are applied and the job (the transaction) is completed. If, however, Access encounters problems while executing the query, the transaction terminates and the log file is discarded without any changes being made. Transaction processing is a very useful safeguard for your data and should always be applied, unless you have a particular reason not to do so.

    The SQL window in the Access Query Designer is also the easiest way to debug SQL statements. Most SQL errors are caused by missing keywords. SQL statements in Access are interpreted by the Jet database engine that runs in the background while Access is running. A missing keyword might generate a generic error:
    "Syntax error (missing operator) in query expression SELECT...."
    Or a more specific error as you narrow down to the faulty part:
    "Syntax error in the ORDER BY clause."
    If you misspell the name of a field or refer to one that doesn't exist:
    "The Microsoft Jet database engine does not recognize LastNme as a valid field name."
    Or you might get an 'Enter Parameter Value' dialog box asking you to entry a value for the misspelled name. This type of error almost always refers to a typo in a field name. General steps to troubleshoot this and most types of errors include:
    * Open the query in design view and make sure that all references to fields are spelled correctly,
    * Check any fields that you recently renamed in the table. This can cause a problem in criteria expressions.
    * If you still can't find the problem, open the data source (usually one or more tables or other queries), and check all of the field names, and then recheck your query.

    Errors generated by faulty SQL statements in VBA are usually not as helpful or specific as those generated in the Query Designer which is why it's best to create and troubleshoot statements in the Query Designer.

    If you want to play around with creating and troubleshooting SQL statements in Access, a good way to do this is to use the Northwind sample database that comes with Access.

  • XBox - Life, What Life?

    Just as Michael Corleone said in Godfather III, "Just when I thought I was out, they pull me back in." I'm not talking about organized crime. I'm talking about XBox. Until about two years ago, I was a major Quake affectionato. I couldn't wait to get home from work to jump back into whatever level I was fighting for my life to get out of. My wife still tells our friends of the physical gyrations I use to make in front of the computer, dodging and ducking to look around corners and avoid being creamed by the demons. And before there was Quake, I was equally hooked on Doom. Back when Doom could fit on a couple of diskettes. The grainy images and cheesy "monsters" were as appealing to me as any spooky movie. For more nights than I count, I'd look at the clock one minute it would be 7pm and look again in what seemed to be 30 minutes later and it would be 1:30am. And that was when I had to leave for work at 5:30am.
    Then about two years ago, I started having this gnawing feeling that I was missing something. It turned out to be a life. I found myself day-dreaming while in meetings on new strategies I could use to get out of this or that situation I'd gotten myself into on the latest level. I even felt guilty because I went to one of those Web sites of Quake tricks and tips.It was like the teenage boy caught by his mother with a girly magazine under his mattress. I kept trying to motivate myself to write my own levels and become a published gamester. Then, one night while laying in bed in the middle of the night trying to figure out a way to conserve ammunition, I came to the realization that I needed to get a hold on myself and find out why my wife stayed mad at me and my children thought I was acting like 10 year old friends.
    So I went cold turkey. Just stopped. Retired my joystick. Put it out of my mind. Oh it was hard for the first few days but gradually, it became easier. It's a shame there wasn't a patch that you could put on your arm to help. I even regain the use in my hand because it wasn't wrapped around the joystick each night. I had used the same technique when I quit smoking in the late 70's although I had some help from my kids then. Whenever I got the urge to smoke, I'd take my kids out into the backyard, put them into their toy wagon, and run around the yard in circles until the urge went away. I put a lot of miles on that wagon. Not to mention making my kids dizzy.
    Now fast forward a couple of years to Christmas 2005. I opened all of my presents, the usual shirts, candy, and "stuff." However, in the corner of the room near the tree was a large box. I had no idea what it could be. I'd had already told my wife to not spend any money on me for Christmas as we had already spent our "Christmas  " money on a trip out east to see my parents. So I opened the box and to my surprise (and horror) was, you guessed it, an XBox. Not the XBox 360 mind you. The old one but an XBox nonetheless. Seems that one of my son-in-laws had driven to New Mexico just after the release of XBox 360 because he couldn't find one where he lived in Denver. Somehow he lucked out and found one in Roswell, NM. Anyway, he and my daughter figured that I had too much time on my hands so I inherited his old box. And like the alcoholic that falls off the wagon, I've become a Halo addict. The old cramps in my hand have returned. I have to forcefully stop myself from strategizing throughout the day. Two Saturday's ago, I went into the guest room, where I've setup the machine (my wife had wisely forbid me from setting it up on our main TV) at 8:30am and didn't come up for air, except for bathroom and water breaks, until 1:30am the next morning. Needless to say, I was wound up like I'd had a bucket of caffenated coffee. Now I once again find myself thinking of strategy, strategy, strategy. This time quitting may not be an option. My kids are too old to ride in the wagon and I'm too old to run around the yard. My boss is even trying to get me to go multiple player online. In the end, the only alternative may be a 12-step program. I plan on looking for one as soon as I finish this level.      

  • It's deja-vu all over again - recursion

    One of the subjects that made me nervous when taking computer science classes in college was recursive programming. It was easy to accidentally write a recursive (i.e. never-ending} program but it was sometimes hard for me to determine when I should write one on purpose. Like any other tool, it is important to know which situations call for recursive programming and which don't. It seemed that as the assignments became more complicated, the more I had to rely on recursive programming.
    A sure-fire way to accidentally end up with an endless loop is to forget to provide some way to terminate a process. A never-ending program eventually runs out of memory to store intermediate results which ends up with an "Out of stack space" error message. Fortunately, this error message in and of itself is a clear sign that you've created an endless loop because it's relatively hard to run out of stack space. Typically, stack space is used to store the arguments of a function when it is called as well as the state of the calling procedure. To run out of stack space, you'd need to have to call a large number of procedures, each within the other. This is kind of what recursion does, except that you can do the same thing with only one procedure if you don't have a way to exit the loop.
    So when is recursion appropriate? Knowing isn't always obvious.If you have a procedure that is carrying out task A and needs to stop and carryout identical task B, then recursion might help. A classic example, is scanning files in folders and sub-folders. The procedure first iterates through the first folder and when it encounters another folder, has to repeat itself. Another example is sorting arrays. You compare two items and then swap one with the other And then you repeat this recursively. Another flag that recursion may help is if you find yourself nesting several loops within themselves.
    One VB.NET program that I currently maintain iterates through the nodes in an XML schema (XSD) and creates a help topic for elements and complex types. The program uses recursion to look for parent elements for elements inside complex types. So the algorithm goes something like this: read through the nodes until you encounter complexType node A. Then continue reading through the nodes inside the type until you find element X. Now read each parent node of element X until you find an element with type A. This element is a parent of element X. If the element is not of type A, continue to read until you find another element and compare its type with type A. Without recursion. imagine how many Do..Until loops and If Then Else loops you would need to move though the element nodes comparing the element's types and then moving to the next element node and so on. With recursion, the amount of code to do this is relatively small. A simplified version is shown here:
        Private Function GetNamedParent(ByVal itemNode As XmlNode, itemType) As XmlNode
            Dim tempParent As XmlNode
            Dim tempTypeNode As XmlNode


            Try
                tempParent = itemNode.ParentNode
                tempTypeNode = tempParent.Attributes("type").Value

                ' Move up the chain until you get to a node with
                ' a name attribute, such as an element or type.
                If tempTypeNode = itemNode.Attributes("type").Value Then
                    Return tempParent
                Else
                    Return GetNamedParent(tempParent)
                End If
            Catch excpt As System.Exception
                '    MessageBox.Show("Error in GetNamedParent function: " & excpt.Message)
            End Try
        End Function 'GetNamedParent

    The function receives the element in the complex type as an argument. The element's parent node is found and assigned to a temporary node variable. Then the parent node's type is compared to the type of the input element. If they match, the temporary element node must be a parent of the input element and its value is returned to the calling procedure. Otherwise the function is called again until a parent is found. Hopefully this explanation has given you a better understanding of recursion and when to use it in your own programs.

More Posts Next page »

© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker