Create a WPF Application with Navigation using PowerShell

In WPF, there are two types of window which can host your application content.  The most commonly used is simply the window (System.Windows.Window in .Net).  But there is another window type, the navigation window (System.Windows.Navigation.NavigationWindow) which takes a slightly different form and includes some basic navigation controls similar to what you would use in a web browser.

capture

This kind of window can be useful in certain situations such as hosting documentation or help content, or recording input over several pages, as the user can go back and forward between the content pages using the navigation history.

The key to making the navigation window work is to use a page control (System.Windows.Control.Page) to host your content.  Like the window, a page can only contain a single child control, so you need to use a layout control like a grid to contain other window elements, such as textboxes and buttons etc.  You can then simply call the relevant page when you navigate.

Below is a simple example of a navigation window which has two actual pages, and the third “page” is a website.  The window itself and the pages are defined in XAML, stored to a hash table, then called by simply setting the Content property of the navigation window. In the case of the web page, we use the navigation service to load the page.

When the window is opened, the first page is displayed:

capture

Clicking next loads the second page:

capture2

 

Clicking next again loads the web page:

capture3

You’ll notice that after you leave the first page the navigation history is enabled and you can go back to the previous pages.

PowerShell Navigation Window


Add-Type -AssemblyName PresentationFramework

# Define Navigation Window in XAML
[XML]$Xaml = @"
<NavigationWindow xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name = "NavWindow" Width = "600" Height = "400" WindowStartupLocation = "CenterScreen" ResizeMode = "CanMinimize" >
</NavigationWindow>
"@

# Define Page 1 text
$Page1_Text1 = @"
Amazon has confirmed its virtual assistant Echo speakers are coming to the UK, Germany and Austria.
Until now, the company sold its voice-controlled devices only in the US.
"@
$Page1_Text2 = @"
The machines can answer questions, control other internet-connected devices, build shopping lists and link in to dozens of third-party services including Spotify, Uber and BBC News.
Experts say they appeal to early adopters' sense of curiosity but tend to be a harder sell to others.
"@

# Define Page 2 text
$Page2_Text1 = @"
The company set up to manufacture Europe's next-generation rocket - the Ariane 6 - says it is open to orders.
Airbus Safran Launchers (ASL) expects to introduce the new vehicle in 2020.
"@
$Page2_Text2 = @"
This week, member states of the European Space Agency gave their final nod to the project following an extensive review process.
The assessment confirmed the design and performance of the proposed rocket, and the development schedule that will bring it into service.
"@

# Define Page 1 in XAML
[XML]$Page1 = @"
<Page      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     x:Name = "Page1" Title="Amazon Echo"     >
    <Grid>
        <StackPanel>
        <TextBlock Padding = "10" TextWrapping = "Wrap" FontFamily = "Segui" FontSize = "18" Height = "Auto" Width = "Auto">
            $Page1_Text1 <LineBreak /><LineBreak />
            $Page1_Text2 <LineBreak />
        </TextBlock>
        <ListBox BorderThickness = "0" Width = "100" HorizontalAlignment = "Left" FontSize = "16">
            <ListBoxItem Content = "That's great!" Foreground = "Green" />
            <ListBoxItem Content = "I hate it!" Foreground = "Red" />
        </ListBox>
        </StackPanel>
        <DockPanel Margin = "480,280,0,0">
            <Button x:Name = "P1_Next" DockPanel.Dock = "Right" Content = "Next" Height = "30" Width = "50" />
        </DockPanel>
    </Grid>
</Page>
"@

# Define Page 2 in XAML
[XML]$Page2 = @"
<Page      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     x:Name = "Page2" Title="Ariane 6"     >
    <Grid>
        <StackPanel>
        <TextBlock Padding = "10" TextWrapping = "Wrap" FontFamily = "Segui" FontSize = "18" Height = "Auto" Width = "Auto">
            $Page2_Text1 <LineBreak /><LineBreak />
            $Page2_Text2 <LineBreak />
        </TextBlock>
        <ListBox BorderThickness = "0" Width = "100" HorizontalAlignment = "Left" FontSize = "16">
            <ListBoxItem Content = "That's great!" Foreground = "Green" />
            <ListBoxItem Content = "I hate it!" Foreground = "Red" />
        </ListBox>
        </StackPanel>
        <DockPanel Margin = "480,280,0,0">
            <Button x:Name = "P2_Next" DockPanel.Dock = "Right" Content = "Next" Height = "30" Width = "50" />
        </DockPanel>
    </Grid>
</Page>
"@

# Create hash table, add WPF named elements and objects
$hash = @{}
$Hash.NavWindow = [Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $xaml))
$Hash.Page1 = [Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $Page1))
$Hash.Page2 = [Windows.Markup.XamlReader]::Load((New-Object -TypeName System.Xml.XmlNodeReader -ArgumentList $Page2))

$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach-Object -Process {
    $hash.$($_.Name) = $hash.NavWindow.FindName($_.Name)
    }
$Page1.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach-Object -Process {
    $hash.$($_.Name) = $hash.Page1.FindName($_.Name)
    }
$Page2.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach-Object -Process {
    $hash.$($_.Name) = $hash.Page2.FindName($_.Name)
    }

# Add code to handle the button click events, loading the next page
$Hash.P1_Next.Add_Click({
    $hash.NavWindow.Content = $Hash.Page2
    $Hash.NavWindow.Title = "Clear path to Ariane 6 rocket introduction"
})

$Hash.P2_Next.Add_Click({
    $Hash.NavWindow.Navigate([URI]"http://www.bbc.com")
    $Hash.NavWindow.Title = "BBC Website"
})

# Set the window content to the first page on load
$hash.NavWindow.Content = $Hash.Page1
$Hash.NavWindow.Title = "Amazon's Echo speakers head to UK and Germany"

# Show the NavWindow
$null = $Hash.NavWindow.Dispatcher.InvokeAsync{$Hash.NavWindow.ShowDialog()}.Wait()

2 thoughts on “Create a WPF Application with Navigation using PowerShell

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.