10

I see a lot of answers, about removing the backstack.

But How do I remove the forward stack?

Aka, Navigating A, to B, to C

A -> B -> C

I then navigate back from C, to B (Form saved, C closed NavigationService.GoBack();)

B <- C

I should now, NOT be able to navigate back to C using the forward button. But have no idea how to implement this. It makes most sense to remove it from the stack somehow.

IAmGroot
  • 13,760
  • 18
  • 84
  • 154
  • Does anyone know how to achieve this? Still struggling with it. – IAmGroot Aug 15 '17 at 09:37
  • Just an idea - when you in B and you somehow know you're back from C, repeat the navigation to B. This should make B the most recent visited element so no way to go to C. Once again, just an idea - didn't give it a try. – Alex Seleznyov Aug 15 '17 at 14:11
  • @AlexSeleznyov Thanks for your suggestion. I have checked if `CanGoForward` then navigate to a copy of itself (B2), and remove the backstack to remove the origional B. It seems like a hacky implementation. As it is essentially having to reload B. But i was reloading the data on the page anyway So not a massive hit. It is a solution, but wonder if there is a better one. Glad its working at least. Thanks! – IAmGroot Aug 15 '17 at 14:48
  • You might also want to dig into NavigationService code - I recall there is a dependency property CanGoForward and some logic around its state so it might worth trying to set that property directly to false. An idea, again. – Alex Seleznyov Aug 16 '17 at 08:22
  • 1
    Did you see this question: https://stackoverflow.com/q/1908675/656243 .. it seems to be exactly what you're looking for. – Lynn Crumbling Aug 18 '17 at 17:12
  • @LynnCrumbling None of the answers remove from the forward stack. And some answers don't work. I'm guessing its not possible, so I'll go with alternative functionality. – IAmGroot Aug 21 '17 at 07:25
  • did you try to handle navigation event? I mean just cancel navigation forward. `NavigatingCancelEventArgs e; if (e.NavigationMode == NavigationMode.Forward) e.Cancel = true;` – vadim_hr Aug 22 '17 at 08:45
  • @vadim_hr The arrow will still show it possible to go forward on navigation bar though? – IAmGroot Aug 22 '17 at 08:53
  • have you tried cancelling it AND this? https://stackoverflow.com/questions/6367876/how-disable-navigation-shortcuts-in-frame-c-sharp-wpf – Deckerz Aug 22 '17 at 08:55
  • Thanks for all the suggestions. I'll give it all a try. – IAmGroot Aug 22 '17 at 09:08
  • @Doomsknight `Page.goForwardButton.IsEnabled = false;` – vadim_hr Aug 22 '17 at 11:00

1 Answers1

0

I know this question was posted long ago, but recently I stumbled upon similar issue and this is how I solved it for my case. I hope it'll help someone.

Requirement

User should be able to go back to pages visited earlier but should not be able to go forward once back button is pressed.

My Approach

Create a custom control derived from Frame and add two addition DPs AllowForwardNavigation and AllowBackNavigation so that I can control if I want to allow prev/next navigation.

MyFrame.xaml.cs

public partial class MyFrame : Frame
{
    #region Dependency Properties
    public bool AllowForwardNavigation
    {
        get { return (bool)GetValue(AllowForwardNavigationProperty); }
        set { SetValue(AllowForwardNavigationProperty, value); }
    }

    public static readonly DependencyProperty AllowForwardNavigationProperty =
        DependencyProperty.Register(nameof(AllowForwardNavigation), typeof(bool), typeof(MyFrame), new PropertyMetadata(true));

    public bool AllowBackNavigation
    {
        get { return (bool)GetValue(AllowBackNavigationProperty); }
        set { SetValue(AllowBackNavigationProperty, value); }
    }

    public static readonly DependencyProperty AllowBackNavigationProperty =
        DependencyProperty.Register(nameof(AllowBackNavigation), typeof(bool), typeof(MyFrame), new PropertyMetadata(true));

    #endregion

    public MyFrame()
    {
        InitializeComponent();

        JournalOwnership = JournalOwnership.OwnsJournal;


        // find existing bindings
        var existingBindings = CommandBindings.OfType<CommandBinding>()
                                              .Where(x => x.Command == NavigationCommands.BrowseForward
                                                       || x.Command == NavigationCommands.BrowseBack)
                                              .ToArray();

        // remove existing bindings
        foreach (var binding in existingBindings)
            CommandBindings.Remove(binding);

        // add new binding
        CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseForward, OnGoForward, OnQueryGoForward));
        CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseBack, OnGoBack, OnQueryGoBack));

        // override default navigation behavior
        NavigationService.Navigating += NavigationService_Navigating;
    }

    private void NavigationService_Navigating(Object sender, NavigatingCancelEventArgs e)
    {
        switch (e.NavigationMode)
        {
            case NavigationMode.Forward:
                e.Cancel = !AllowForwardNavigation;
                break;
            case NavigationMode.Back:
                e.Cancel = !AllowBackNavigation;
                break;
        }
    }

    #region Command methods
    private void OnGoForward(Object sender, ExecutedRoutedEventArgs e)
    {
        e.Handled = true;
        if (AllowForwardNavigation && NavigationService.CanGoForward)
            NavigationService.GoForward();
    }

    private void OnQueryGoForward(Object sender, CanExecuteRoutedEventArgs e)
    {
        e.Handled = true;
        e.CanExecute = AllowForwardNavigation && NavigationService.CanGoForward;
    }

    private void OnGoBack(Object sender, ExecutedRoutedEventArgs e)
    {
        e.Handled = true;
        if (AllowBackNavigation && NavigationService.CanGoBack)
            NavigationService.GoBack();
    }

    private void OnQueryGoBack(Object sender, CanExecuteRoutedEventArgs e)
    {
        e.Handled = true;
        e.CanExecute = AllowBackNavigation && NavigationService.CanGoBack;
    }
    #endregion
}

MyFrame.xaml

            <Style x:Key="NavigationWindowBackButtonStyle" TargetType="{x:Type Button}">
                <Setter Property="OverridesDefaultStyle" Value="true"/>
                <Setter Property="Command" Value="NavigationCommands.BrowseBack"/>
                <Setter Property="Focusable" Value="false"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Grid Background="Transparent" Height="24" Width="24">
                                <Ellipse x:Name="Circle" Fill="{StaticResource NavigationWindowNavigationButtonFillEnabled}" Stroke="{StaticResource NavigationWindowNavigationButtonStrokeEnabled}" StrokeThickness="1"/>
                                <Path x:Name="Arrow" Data="M0.37,7.69 L5.74,14.20 A1.5,1.5,0,1,0,10.26,12.27 L8.42,10.42 14.90,10.39 A1.5,1.5,0,1,0,14.92,5.87 L8.44,5.90 10.31,4.03 A1.5,1.5,0,1,0,5.79,1.77 z" Fill="{StaticResource NavigationWindowNavigationArrowFill}" HorizontalAlignment="Center" Stroke="{StaticResource NavigationWindowNavigationArrowStrokeEnabled}" StrokeThickness="0.75" VerticalAlignment="Center"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillDisabled}"/>
                                    <Setter Property="Stroke" TargetName="Circle" Value="#B5BACE"/>
                                    <Setter Property="Stroke" TargetName="Arrow" Value="#B0B5BACE"/>
                                    <Setter Property="Fill" TargetName="Arrow" Value="#D0FFFFFF"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillHover}"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillPressed}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="NavigationWindowForwardButtonStyle" TargetType="{x:Type Button}">
                <Setter Property="OverridesDefaultStyle" Value="true"/>
                <Setter Property="Command" Value="NavigationCommands.BrowseForward"/>
                <Setter Property="Focusable" Value="false"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Grid Background="Transparent" Height="24" Width="24">
                                <Ellipse x:Name="Circle" Grid.Column="0" Fill="{StaticResource NavigationWindowNavigationButtonFillEnabled}" Stroke="{StaticResource NavigationWindowNavigationButtonStrokeEnabled}" StrokeThickness="1"/>
                                <Path x:Name="Arrow" Grid.Column="0" Data="M0.37,7.69 L5.74,14.20 A1.5,1.5,0,1,0,10.26,12.27 L8.42,10.42 14.90,10.39 A1.5,1.5,0,1,0,14.92,5.87 L8.44,5.90 10.31,4.03 A1.5,1.5,0,1,0,5.79,1.77 z" Fill="{StaticResource NavigationWindowNavigationArrowFill}" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0" Stroke="{StaticResource NavigationWindowNavigationArrowStrokeEnabled}" StrokeThickness="0.75" VerticalAlignment="Center">
                                    <Path.RenderTransform>
                                        <ScaleTransform ScaleX="-1"/>
                                    </Path.RenderTransform>
                                </Path>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillDisabled}"/>
                                    <Setter Property="Stroke" TargetName="Circle" Value="#B5BACE"/>
                                    <Setter Property="Stroke" TargetName="Arrow" Value="#B0B5BACE"/>
                                    <Setter Property="Fill" TargetName="Arrow" Value="#D0FFFFFF"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillHover}"/>
                                </Trigger>
                                <Trigger Property="IsPressed" Value="true">
                                    <Setter Property="Fill" TargetName="Circle" Value="{StaticResource NavigationWindowNavigationButtonFillPressed}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Frame.Resources>
    <Frame.Template>
        <ControlTemplate TargetType="Frame">
            <DockPanel Margin="7">
                <StackPanel Visibility="{TemplateBinding NavigationUIVisibility}" Margin="0" Orientation="Horizontal"
                            DockPanel.Dock="Top">
                    <Button Style="{StaticResource NavigationWindowBackButtonStyle}"
                            Command="NavigationCommands.BrowseBack"
                            Content="M 4 0 L 0 4 L 4 8 Z"
                            Margin="2.7,0,1.3,0" />
                    <Button Style="{StaticResource NavigationWindowForwardButtonStyle}"
                            Command="NavigationCommands.BrowseForward"
                            Content="M 4 0 L 0 4 L 4 8 Z" Margin="1.3,0,0,0" />
                </StackPanel>

                <Border>
                    <ContentPresenter />
                </Border>
            </DockPanel>
        </ControlTemplate>
    </Frame.Template>
</Frame>

Usage

<local:MyFrame x:Name="_mainFrame" NavigationUIVisibility="Visible" 
               AllowForwardNavigation="False" />
Dipen Shah
  • 25,562
  • 1
  • 32
  • 58