Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C#
Article

Microsoft Office Word Navigation

Rate me:
Please Sign up or sign in to vote.
4.67/5 (4 votes)
11 Dec 2008CPOL2 min read 29.2K   494   20  
An article on navigation inside a Word document

Word 2007
2007.png

Word 2003
Image 2

Introduction

As you know, there's a really nice feature in Visual Studio called Navidate forward/backward. I started to look for this feature inside Microsoft Word (2003 and later) that works exactly like the one in Visual Studio. After some Googling, I found that Word has a functionality that should solve the problem but has a bug since Word 2000. This functionality is SHIFT+F5.

Using the Code

The most important thing in this project is to keep in some kind of data strucure all navigation locations that we made inside the documents (cursor's moves). For that I've used a simple (but very useful) data structure called "Stack." The stack is a LIFO (Last In First Out) structure and it's perfect for our job. Everytime we "navigate" inside the document we add (or Push) that location to the stack.

You may wonder what this location is that I am talking about... It's nothing more than a Range element and if you'll look inside MSDN for the definition of this class, a Range is "a contiguous area in a document"(for example, Paragraph, Bookmark, Cell or Picture). This interface is in the Microsoft.Office.Interop.Word namespace.

C#
[Guid("0002095E-0000-0000-C000-000000000046")]
[TypeLibType(4288)]
public interface Range
{
   ...

}

Managing Events

So, how do we catch these navigation events? The ApplicationClass has a WindowSelectionChange event that is triggered every time the selection of an object has changed. So, we're going to implement that event.

In the ThisAddIn_Startup method, we create the navigation buttons and register our handler for the WindowSelectionChange event.

C#
ApplicationClass __MyApplication;
Office.CommandBar commandBar;
Office.CommandBarButton __BackwardButton;
Office.CommandBarButton __ForwardButton;

string __NavigateBackwardTag = "Navigate backward";
string __NavigateForwardTag = "Navigate foreward";

Stack<Range> __MyBackwardStack = new Stack<Range>();
Stack<Range> __MyForwardStack = new Stack<Range>();

bool __FromBack, __FromFore;

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
	this.BackNavigationToolbar();
	this.ForwardNavigationToolbar();

	this.__MyApplication = this.Application as ApplicationClass;

	__MyApplication.ApplicationEvents3_Event_WindowSelectionChange += 
             new ApplicationEvents3_WindowSelectionChangeEventHandler(
             __MyApplication_ApplicationEvents3_Event_WindowSelectionChange);
}

void __MyApplication_ApplicationEvents3_Event_WindowSelectionChange(Selection Sel)
{
	if (__FromBack == false && __FromFore == false)
		__MyBackwardStack.Push(Sel.Range);
	else
	{
		
		if (__FromBack == true)
			__FromBack = false;

		if (__FromFore == true)                
			__FromFore = false;
	}
}

As you can see I start by declaring some variables for later use. After that we add the navigation buttons to the Standard toolbar.

C#
private void BackNavigationToolbar()
{
	try
	{
		commandBar = this.Application.CommandBars["Standard"];
	}
	catch (Exception e)
	{
		MessageBox.Show(e.Message);
	}

	try
	{
		__BackwardButton = commandBar.FindControl(1, missing,
                      __NavigateBackwardTag, missing, true) as Office.CommandBarButton;

		if (__BackwardButton == null)
		{
			// Add a button to the command bar and an event handler.
			__BackwardButton = 
                               (Office.CommandBarButton)commandBar.Controls.Add(1,
                               missing, missing, missing, true);
		}
		__BackwardButton.Style = Office.MsoButtonStyle.msoButtonIconAndCaption;
		__BackwardButton.Caption = "Navigate backward";
		__BackwardButton.Tag = __NavigateBackwardTag;
		__BackwardButton.Picture = PictureDispConverter.ToIPictureDisp(
                      Resources.back);

		__BackwardButton.Click += delegate(CommandBarButton Ctrl,
                      ref bool CancelDefault)
		{
			try
			{
				if (__MyBackwardStack.Count > 0)
				{
					//Pop the last element
					Range rng = this.__MyBackwardStack.Pop();
					//add it to other stack
					this.__MyForwardStack.Push(rng);
					__FromBack = true;
					//set range
					this.__MyApplication.Selection.SetRange(
                                                  rng.Start, rng.End);
					//select it
					rng.Select();
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}

		};
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

and after that I handle the WindowSelectionChange event.

So, each time we navigate inside the document, we add the Range object into the stack. But what happens when we click on the navigation buttons? When we click on "Navigate backward" button, we call the Pop() method, Push(...) the Range to the other stack(for Navigation Forward) and then set the Selection.Range. After that we call Select() the Range.

The same thing happens when we click on the "Navigate foreward" button.

Because the Select() method triggers the WindowSelectionChange event, we don't want to add the same Range to the stack. That's why I used the __FromBack and __FromFore fields.

History

version 0.1.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Romania Romania
is a developer at LetsVR.ro.

Comments and Discussions

 
-- There are no messages in this forum --