Linear Navigation
Now that you've had an introduction to page navigation in WPF applications, it's time for some vital specifics. There are basically two main types of navigations in WPF:
In a linear navigation, all pages are strung together and one loads after another.
Figure 10 shows three pages all linked up in a linear fashion. For hierarchical navigation, the pages are linked in a tree-like structure. I will discuss hierarchical navigation in the next section.

Figure 10. Linear Navigation: The three pages of the application have a linear relationship.
|
|

Figure 11. Page1.xaml: Here's the first page of the new application, which will use linear navigation. |
I'll now create a simple application to show how linear navigation works. Using Visual Studio 2005, create a new WPF (Avalon) Navigation application. With the default
Page1.xaml page, add two more PageFunction pages and name them
Page2.xaml and
Page3.xaml. I will also take this chance to illustrate the different types of page function pages.
Populate Page1.xaml as follows:
<Page x:Class="Page1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
>
<DockPanel>
<StackPanel DockPanel.Dock="Left"
Background="LightBlue">
<TextBlock Margin="10,10,10,10">
Page 1</TextBlock>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="LightYellow">
<TextBlock Margin="10,10,10,10">
Enter your name</TextBlock>
<TextBox Name="txtName" Margin="10,10,10,10"
Width="200"
HorizontalAlignment="Left"></TextBox>
<Button Click="ButtonClick" Name="btnNextPage"
Margin="10,10,10,10" Width="80"
HorizontalAlignment="Left">Next Page</Button>
<Button Click="ButtonClick" Name="btnExit"
Margin="10,10,10,10" Width="80"
HorizontalAlignment="Left">Exit</Button>
<TextBlock Margin="10,10,10,10">
<Inline Name="returnString" />
</TextBlock>
</StackPanel>
</DockPanel>
</Page>
Figure 11 shows how
Page1.xaml will look like when loaded.
In the code-behind, Page1.xaml.vb, code the following:
Partial Public Class Page1
Inherits Page
Public WithEvents nextPage As Page2
'---used for preserving the name entered in this page
Private Shared _Name As String
Private Sub OnLoaded( _
ByVal sender As Object, _
ByVal e As RoutedEventArgs) Handles Me.Loaded
txtName.Text = _Name
End Sub
Private Sub ButtonClick( _
ByVal sender As Object, _
ByVal e As RoutedEventArgs)
Dim myApp As NavigationApplication
Dim navWindow As NavigationWindow
myApp = CType( _
System.Windows.Application.Current, _
NavigationApplication)
navWindow = CType(myApp.MainWindow, _
NavigationWindow)
'---navigate to next page---
If sender.Equals(btnNextPage) Then
'---save the name entered
_Name = txtName.Text
nextPage = New Page2
nextPage.InitializeComponent()
navWindow.Navigate(nextPage)
End If
'---exit the application---
If sender.Equals(btnExit) Then
System.Windows.Application.Current.Shutdown()
End If
End Sub
Private Sub nextPage_Return( _
ByVal sender As Object, _
ByVal args As StringReturnEventArgs) Handles _
nextPage.Return
'---display the string entered in the next window
returnString.Text = "From Page 2: " & _
args.Result.ToString
End Sub
End Class
Here are the important points to note for this page:
- The ButtonClick() method is fired when either the Next Page button or the Exit button is clicked.
- If the Next Page button is clicked, the application navigates to Page2.xaml. If the Exit button is clicked, the application quits.
- Before the application navigates to the Page2.xaml, the name entered by the user must be preserved using a shared variable. This is because when you navigate between pages (either programmatically or using the navigational buttons) the state of the page is not preserved. Therefore you need to maintain your own state.
- The OnLoaded() method is fired whenever the page is loaded, so this is the place to set the value of controls to their original values/state.
- The nextPage_Return() method is fired when Page2.xaml returns a value to it.
Populate
Page2.xaml as follows:
<StringPageFunction x:Class="Page2"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
>
<DockPanel>
<StackPanel DockPanel.Dock="Left"
Background="LightBlue">
<TextBlock Margin="10,10,10,10">
Page 2</TextBlock>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="LightYellow">
<TextBlock Margin="10,10,10,10">
Enter your company name</TextBlock>
<TextBox Name="txtCompanyName"
Margin="10,10,10,10"
Width="200" HorizontalAlignment="Left">
</TextBox>
<DockPanel>
<Button DockPanel.Dock="Left"
Click="ButtonClick"
Name="btnPreviousPage"
Margin="10,10,10,10"
Width="80" HorizontalAlignment="Left">
Previous Page</Button>
<Button DockPanel.Dock="Right"
Click="ButtonClick"
Name="btnNextPage" Margin="10,10,10,10"
Width="80" HorizontalAlignment="Left">
Next Page</Button>
</DockPanel>
<Button Click="ButtonClick" Name="btnExit"
Margin="10,10,10,10" Width="80"
HorizontalAlignment="Left">Exit</Button>
<TextBlock Margin="10,10,10,10">
<Inline Name="returnString" />
</TextBlock>
</StackPanel>
</DockPanel>
</StringPageFunction>
Note that
Page2.xaml is a StringPageFunction, which means it will return a string value back to the calling page.
Figure 12 shows how
Page2.xaml will look like when loaded.
 | |
| Figure 12. Page2.xaml: Here's the second page of the application, which returns a string to the first page. |
In the code-behind,
Page2.xaml.vb, code the following:
Partial Public Class Page2
Inherits StringPageFunction
Public WithEvents nextPage As Page3
'---used for preserving the company name entered
' in this page
Private Shared _CompanyName As String
Private Sub OnLoaded(ByVal sender As Object, _
ByVal e As RoutedEventArgs) Handles Me.Loaded
txtCompanyName.Text = _CompanyName
End Sub
Private Sub ButtonClick(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
Dim myApp As NavigationApplication
Dim navWindow As NavigationWindow
myApp = CType( _
System.Windows.Application.Current, _
NavigationApplication)
navWindow = CType(myApp.MainWindow, _
NavigationWindow)
'---navigate to next page---
If sender.Equals(btnNextPage) Then
_CompanyName = txtCompanyName.Text
nextPage = New Page3
nextPage.InitializeComponent()
navWindow.Navigate(nextPage)
End If
If sender.Equals(btnPreviousPage) Then
OnFinish(txtCompanyName.Text)
End If
'---exit the application---
If sender.Equals(btnExit) Then
System.Windows.Application.Current.Shutdown()
End If
End Sub
Private Sub nextPage_Return(ByVal sender As Object, _
ByVal args As BooleanReturnEventArgs) Handles _
nextPage.Return
'---display the string entered in the next window
returnString.Text = "From Page 3: " & _
args.Result.ToString
End Sub
End Class
Basically,
Page2.xaml.vb is very similar to
Page1.xaml.vb, except that when the Previous Page button is clicked, it returns the company name entered back to the calling page using the
OnFinish() method. The Next Page button will cause the application to navigate to
Page3.xaml.
Finally, populate Page3.xaml as follows:
<BooleanPageFunction x:Class="Page3"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
>
<DockPanel>
<StackPanel DockPanel.Dock="Left"
Background="LightBlue">
<TextBlock Margin="10,10,10,10">
Page 3</TextBlock>
</StackPanel>
<StackPanel DockPanel.Dock="Right"
Background="LightYellow">
<TextBlock Margin="10,10,10,10">
Single?</TextBlock>
<RadioButtonList Margin="10,10,10,10">
<RadioButton Name="rbTrue">True</RadioButton>
<RadioButton Name="rbFalse">False
</RadioButton>
</RadioButtonList>
<DockPanel>
<Button DockPanel.Dock="Left"
Click="ButtonClick"
Name="btnPreviousPage"
Margin="10,10,10,10"
Width="80" HorizontalAlignment="Left">
Previous Page</Button>
</DockPanel>
<Button Click="ButtonClick" Name="btnExit"
Margin="10,10,10,10" Width="80"
HorizontalAlignment="Left">Exit</Button>
</StackPanel>
</DockPanel>
</BooleanPageFunction>
Note that
Page3.xaml is a BooleanPageFunction, which returns a Boolean result back to the calling page.
Figure 13 shows how
Page3.xaml will look like when loaded.

Figure 13. Page3.xaml: The final page in this three-page application asks for a simple Boolean, which is returned to page 2.
|
|

Figure 14. Flow of the Application: The three pages of this linear application go forward through pages 1, 2, and 3, sequentially, and then back in reverse order. |
In the code-behind,
Page3.xaml.vb, code the following:
Partial Public Class Page3
Inherits BooleanPageFunction
'---used for preserving the maritial status
' selected in this page
Private Shared _Status As Boolean
' Sample event handlers:
Private Sub OnLoaded(ByVal sender As Object, _
ByVal e As RoutedEventArgs) Handles Me.Loaded
If _Status = True Then
rbTrue.IsChecked = True
Else
rbFalse.IsChecked = True
End If
End Sub
Private Sub ButtonClick(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
If sender.Equals(btnPreviousPage) Then
If rbTrue.IsChecked = True Then
_Status = True
Else
_Status = False
End If
OnFinish(_Status)
End If
'---exit the application---
If sender.Equals(btnExit) Then
System.Windows.Application.Current.Shutdown()
End If
End Sub
End Class
Now you can run the application and trace the flow (see
Figure 14).