This project is read-only.

Previous next command for modern tab?

Feb 25, 2014 at 12:58 PM
I'm writing a wizard using a ModernTab and want previous next buttons, could not find commands for navigating a linkcollection but feel there should be.
Are there built in commands or a nice way to do this?
Feb 25, 2014 at 5:10 PM
Bind your ModernTab's SelectedSource to a property in your ViewModel and keep track of the current page. Then have your button's Command in your VM simply set the SelectedSource property to the proper one, and bingo.
Feb 25, 2014 at 5:45 PM
Edited Feb 25, 2014 at 6:26 PM
Yeah that is a way, I'm not sure I love it though. Want to write all the links in xaml, writing it this way would mean that the view (tab) would send its linkcollection to the vm. Think I prefer hacking it in code behind but that is not very clean either perhaps. Gonna think about this for a while.

Wrote this:
<mui:ModernTab x:Name="Tab" Layout="Tab" HorizontalAlignment="Left" Grid.RowSpan="2"
               SelectedSource="/Data.xaml">
    <mui:ModernTab.Links>
        <mui:Link DisplayName="Data" Source="/Data.xaml"/>
        <mui:Link DisplayName="Summary" Source="/Summary.xaml"/>
    </mui:ModernTab.Links>
</mui:ModernTab>
<StackPanel Orientation="Horizontal" Grid.Row="1" TextBlock.FontSize="18" Margin="0,10,0,0">
    <Button Content="{l:Translate Next}" 
            Margin="15,0,0,0" 
            Command="BrowseForward" 
            CommandTarget="{Binding ElementName=Tab}">
        <Button.CommandParameter>
            <MultiBinding Converter="{StaticResource NextTabConverter}">
                <Binding ElementName="Tab"/>
                <Binding ElementName="Tab" Path="SelectedSource"/>
            </MultiBinding>
        </Button.CommandParameter>
    </Button>
</StackPanel>
    public class NextTabConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var tab = values.OfType<ModernTab>().FirstOrDefault();
            if (tab == null)
                return null;
            var current = tab.Links.Single(x => x.Source == tab.SelectedSource);
            var i = tab.Links.IndexOf(current) + 1;
            if (i == tab.Links.Count)
                return null;
            return tab.Links[i].Source;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
But it does not navigate the frame inside the tab
Ideally I'm looking for something like:
<Button Content="Previous"
        Command="NextTabCommand"
        CommandTarget="{Binding ElementName=Tab}"/>
Feb 25, 2014 at 7:28 PM
Johan20D wrote:
Yeah that is a way, I'm not sure I love it though. Want to write all the links in xaml, writing it this way would mean that the view (tab) would send its linkcollection to the vm.
No. You can still define the links in the xaml, just bind the SelectedSource property to one in the VM.
Feb 25, 2014 at 8:41 PM
Edited Feb 25, 2014 at 8:55 PM
I wrote it like this:
    using System.Linq;
    using System.Windows.Input;
    using FirstFloor.ModernUI.Windows.Controls;
    public static class ModernCommands
    {
        static ModernCommands()
        {
            var nextBinding = new CommandBinding(ModernCommands.NextTab, ExecuteNextTab, CanExecuteNextTab);
            CommandManager.RegisterClassCommandBinding(typeof(ModernTab), nextBinding);
            var prevBinnding = new CommandBinding(ModernCommands.PreviousTab, ExecutePreviousTab, CanExecutePreviousTab);
            CommandManager.RegisterClassCommandBinding(typeof(ModernTab), prevBinnding);
        }

        private static readonly RoutedCommand Next = new RoutedCommand("NextTab", typeof(ModernCommands));

        private static readonly RoutedCommand Previous = new RoutedCommand("PreviousTab", typeof(ModernCommands));

        public static RoutedCommand NextTab
        {
            get
            {
                return Next;
            }
        }
        public static RoutedCommand PreviousTab
        {
            get
            {
                return Previous;
            }
        }
        private static void CanExecuteNextTab(object sender, CanExecuteRoutedEventArgs e)
        {
            var tab = sender as ModernTab;
            if (tab == null || tab.SelectedSource == null)
            {
                e.CanExecute = false;
                return;
            }
            e.CanExecute = IsInRange(CurrentIndex(tab) + 1, tab);
        }
        private static void ExecuteNextTab(object sender, ExecutedRoutedEventArgs e)
        {
            var tab = (ModernTab)sender;
            tab.SelectedSource = tab.Links[CurrentIndex(tab) + 1].Source;
        }
        private static void CanExecutePreviousTab(object sender, CanExecuteRoutedEventArgs e)
        {
            var tab = sender as ModernTab;
            if (tab == null || tab.SelectedSource == null)
            {
                e.CanExecute = false;
                return;
            }
            e.CanExecute = IsInRange(CurrentIndex(tab) - 1, tab);
        }
        private static void ExecutePreviousTab(object sender, ExecutedRoutedEventArgs e)
        {
            var tab = (ModernTab)sender;
            tab.SelectedSource = tab.Links[CurrentIndex(tab) - 1].Source;
        }
        private static int CurrentIndex(ModernTab tab)
        {
            return tab.Links.IndexOf(tab.Links.FirstOrDefault(x => x.Source == tab.SelectedSource));
        }
        private static bool IsInRange(int i, ModernTab tab)
        {
            return i < tab.Links.Count && i > -1;
        }
    }
Lets me do:
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <mui:ModernTab Layout="Tab" x:Name="Tab">
            <mui:ModernTab.Links>
                <mui:Link DisplayName="Language" Source="/View1.xaml" />
                <mui:Link DisplayName="Item 2" Source="/View2.xaml" />
            </mui:ModernTab.Links>
        </mui:ModernTab>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Content="Previous" 
                Command="commands:ModernCommands.PreviousTab"
                CommandTarget="{Binding ElementName=Tab}"/>
            
            <Button Content="Next" 
                Command="commands:ModernCommands.NextTab"
                CommandTarget="{Binding ElementName=Tab}"/>
        </StackPanel>

    </Grid>
Marked as answer by Johan20D on 2/25/2014 at 3:30 PM