views:

1874

answers:

3

I'm trying to use the navigation command framework in WPF to navigate between Pages within a WPF application (desktop; not XBAP or Silverlight).

I believe I have everything configured correctly, yet its not working. I build and run without errors, I'm not getting any binding errors in the Output window, but my navigation button is disabled.

Here's the app.xaml for a sample app:

<Application x:Class="Navigation.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="First.xaml">
</Application>

Note the StartupUri points to First.xaml. First.xaml is a Page. WPF automatically hosts my page in a NavigationWindow. Here's First.xaml:

<Page x:Class="Navigation.First"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="First">
    <Grid>
        <Button 
            CommandParameter="/Second.xaml" 
            CommandTarget="{Binding RelativeSource=
                {RelativeSource 
                    FindAncestor, 
                    AncestorType={x:Type NavigationWindow}}}" 
            Command="NavigationCommands.GoToPage" 
            Content="Go!"/>
    </Grid>
</Page>

The button's CommandTarget is set to the NavigationWindow. The command is GoToPage, and the page is /Second.xaml. I've tried setting the CommandTarget to the containing Page, the CommandParameter to "Second.xaml" (First.xaml and Second.xaml are both in the root of the solution), and I've tried leaving the CommandTarget empty. I've also tried setting the Path to the Binding to various navigational-related public properties on the NavigationWindow. Nothing has worked so far.

What am I missing here? I really don't want to do my navigation in code.


Clarification.

If, instead of using a button, I use a Hyperlink:

<Grid>
    <TextBlock>
       <Hyperlink 
           NavigateUri="Second.xaml">Go!
       </Hyperlink>
    </TextBlock>
</Grid>

everything works as expected. However, my UI requirements means that using a Hyperlink is right out. I need a big fatty button for people to press. That's why I want to use the button to navigate. I just want to know how I can get the Button to provide the same ability that the Hyperlink does in this case.

+1  A: 

According to the documentation, only DocumentViewer and FlowDocumentViewer implement this command specifically. You'll need to either find a command for navigation that NavigationWindow implements, or set up a CommandBinding for this command and handle it yourself.

Andy
Thanks, but that isn't exactly applicable in this case. I've edited my question to hopefully clarify it. I'm trying to find a way for the button to Command the NavigationWindow where to go next. My code doesn't work, so I'm not insisting that it be done that way. I'm looking for a way to get a button to work with the NavigationWindow.
Will
Essentially this is the only way to do this. I'm using Commands in my VM to hook the buttons to. The base view model holds a reference to the main window's navigation service.
Will
+1  A: 

You will want to use the NavigationService of your NavigationWindow as follows:

XAML:

    <Button HorizontalAlignment="Right" Name="continueButton" Width="75" Margin="0,0,8,11" Height="23" VerticalAlignment="Bottom" Click="continueButton_Click">
        Continue
    </Button>

C#:

    private void continueButton_Click(object sender, RoutedEventArgs e)
    {
        this.NavigationService.GoForward();
        //or
        this.NavigationService.Navigate("Second.xaml")
    }

With either of this you can use use this, I only show the NavigationService here for clarity

karbon
This works, but for MVVM the command pattern is preferable. Thanks for the answer.
Will
+1  A: 

In XAML:

<Button Command="{x:Static Views:Commands.NavigateHelp}" Content="Help"/>

In Views (We have a Commands.cs file that contains all of these):

public static RoutedCommand NavigateHelp = new RoutedCommand();

In the Page contstructor, you can connect the two:

CommandBindings.Add(new CommandBinding(Commands.NavigateHelp, NavigateHelpExecute));

NavigateHelpExecute can be in the code behind (which is what we do), hook into a ViewModel event handler, or whatever. The beauty of this is that you can disable other navigation like so:

CommandBindings.Add(new CommandBinding(NavigationCommands.Refresh, null));

Hope this helps.

Nate Noonen