1

With the following code I can create a non wrapped scrolling stackpanel of headers of a tabcontrol. It has repeat buttons that can control the scroll. I would like instead for the repeat buttons to be able to control which tab is active, and adjust the scroll so the active tab can scroll into view. Is such a thing possible?

<TabControl SelectedItem="{Binding ActiveTicketFilterTab, Mode=TwoWay}" 
                                Margin="5"  
                                Grid.Row="1" 
                                BorderBrush="Gray"
                                BorderThickness="2"
                                Style="{StaticResource ResourceKey=somestyle}" 
                                SelectionChanged="selectionchanged" 
                                Name="somename" 
                                Background="#252525"
                                ItemsSource="{Binding someobslist}" 
                                Grid.ColumnSpan="2">
                        <TabControl.Resources>
                            <Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate>
                                            <Border Background="sc#1, 0.366693377, 0.372125238, 0.6931424">
                                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
                                            </Border>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </TabControl.Resources>

                        <TabControl.Template>
                            <ControlTemplate TargetType="{x:Type TabControl}">
                                <Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                                        <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                                        <RowDefinition x:Name="RowDefinition1" Height="*"/>
                                    </Grid.RowDefinitions>
                                    <ScrollViewer  Panel.ZIndex="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
                                        <ScrollViewer.Style>
                                            <Style TargetType="{x:Type ScrollViewer}">
                                                <Setter Property="Template">
                                                    <Setter.Value>
                                                        <ControlTemplate>
                                                            <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                                                                <Grid.ColumnDefinitions>
                                                                    <ColumnDefinition Width="*"/>
                                                                    <ColumnDefinition Width="50"/>
                                                                </Grid.ColumnDefinitions>
                                                                <Grid.RowDefinitions>
                                                                    <RowDefinition Height="Auto"/>
                                                                </Grid.RowDefinitions>

                                                                <ScrollContentPresenter Grid.Column="0" Content="{TemplateBinding ScrollViewer.Content}" />
                                                                <StackPanel Orientation="Horizontal"  Grid.Column="1">
                                                                    <RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="&lt;" Command="ScrollBar.LineLeftCommand"/>
                                                                    <RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="&gt;" Command="ScrollBar.LineRightCommand"/>
                                                                </StackPanel>
                                                            </Grid>
                                                        </ControlTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </ScrollViewer.Style>
                                        <StackPanel  x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" Orientation="Horizontal"/>
                                    </ScrollViewer>
                                        <Border x:Name="ContentPanel" 
                                            BorderBrush="{TemplateBinding BorderBrush}" 
                                            BorderThickness="{TemplateBinding BorderThickness}" 
                                            Background="{TemplateBinding Background}" 
                                            Grid.Row="1"
                                            Grid.Column="0" 
                                            Margin="2,-2, 0, 13"
                                            KeyboardNavigation.DirectionalNavigation="Contained" 
                                            KeyboardNavigation.TabIndex="2" 
                                            KeyboardNavigation.TabNavigation="Local">
                                        <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Border>
                                </Grid>
                            </ControlTemplate>
                        </TabControl.Template>



                        <TabControl.ItemContainerStyle>
                            <Style TargetType="TabItem" BasedOn="{StaticResource someotherstyle}">
                                <Setter Property="HeaderTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <Border BorderBrush="{x:Null}" Height="25">
                                                <TextBlock Padding="10"  Name="Title"  VerticalAlignment="Center" TextTrimming="CharacterEllipsis"  HorizontalAlignment="Stretch" Text="{Binding Name}" ToolTip="{Binding Name}" />
                                            </Border>
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </TabControl.ItemContainerStyle>
                        <TabControl.ContentTemplate>
                            <DataTemplate>
                                <Grid Background="Transparent">
                                    <ListBox    x:Name="ticketView"   
                                                Unloaded="On_Listbox_enter"
                                                ItemsSource="{Binding TicketsView}"
                                                Background="#252525"
                                                Margin="5,5,0,0"
                                                HorizontalContentAlignment="Stretch"
                                                BorderBrush="{x:Null}"
                                                BorderThickness="1" 
                                                Padding="0,0,5,0"
                                                VirtualizingPanel.IsVirtualizing="False"
                                                ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                                ScrollViewer.VerticalScrollBarVisibility="Auto"
                                                ScrollViewer.CanContentScroll="False" 
                                                ItemTemplate="{StaticResource TicketViewTemplate}">
                                        <ListBox.Resources>
                                            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#252525" />
                                            <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />                                           
                                        </ListBox.Resources>
                                    </ListBox>

                                    <StackPanel Grid.Row="0" Margin="328,75"
                                            Visibility="{Binding ExposeTicketSpinner, Converter={StaticResource BoolToVisConverter}}" 
                                            Width="Auto">

                                        <Viewbox Grid.Row="0"
                                             Height="100"
                                             Width="100"
                                             HorizontalAlignment="Stretch" 
                                             VerticalAlignment="Stretch">
                                            <WPFControls:CircularProgressBar HorizontalAlignment="Center" VerticalAlignment="Center" />
                                        </Viewbox>
                                        <Label Foreground="White" FontWeight="Bold"  Margin="0,33"  Content="Loading Tickets..." HorizontalAlignment="Center"></Label>
                                    </StackPanel>
                                </Grid>
                            </DataTemplate>
                        </TabControl.ContentTemplate>
                    </TabControl>
lokusking
  • 7,396
  • 13
  • 38
  • 57
cool mr croc
  • 725
  • 1
  • 13
  • 33
  • Just replace the `ScrollBar.LineLeftCommand` and of course LineRightCommand with your own command and logic – lokusking Aug 04 '16 at 15:32
  • I would do that if I could get the scrollviewer to scroll the right amount of pixels but all I can see is linemove. I thought setting the cancontentscroll to true would mean a linemove would be an entire tab but it doesn't work. – cool mr croc Aug 04 '16 at 16:03

1 Answers1

1

To get your things to work as desired, do the following:

First

Replace your Repeatbuttons with this

<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="&lt;" Command="{Binding MoveLeftCommand}"/>
<RepeatButton Style="{StaticResource TabScrollerRepeatButtonStyle}" Content="&gt;" Command="{Binding MoveRightCommand}"/>

Second

In your ViewModel (That holds the TabControl) do it like this:

public ICommand MoveLeftCommand => new RelayCommand(x => {
            var currIdx = this.someobslist.IndexOf(this.ActiveTicketFilterTab);
            this.ActiveTicketFilterTab = currIdx == 0 ? this.someobslist[this.someobslist.Count - 1] : this.someobslist[currIdx - 1];
        });

        public ICommand MoveRightCommand => new RelayCommand(x => {
            var currIdx = this.someobslist.IndexOf(this.ActiveTicketFilterTab);
            this.ActiveTicketFilterTab = currIdx == this.someobslist.Count - 1 ? this.someobslist[0] : this.someobslist[currIdx + 1];
        });

Thats it. In case you need a RelayCommand, i can hand you mine. Of course replace my Varaibles with yours.

This Solution circles now through the TabItems

EDIT

Here is a plain scrollcycler without navigating to the TabItem, based on this <--- IMPORTANT

Add to your ScrollViewer a Loaded-Event in XAML

Here the code:

private int _scollMoverIdx = 0;
    private TabControl _container;

    private void ScrollViewer_OnLoaded(object sender, RoutedEventArgs e) {
      this._container = (sender as ScrollViewer).TemplatedParent as TabControl;
    }

    public ICommand MoveLeftCommand => new RelayCommand(x => {
      if (this._scollMoverIdx == 0) {
        this._scollMoverIdx = this.someobslist.Count - 1;
        this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
      } else {
        _scollMoverIdx--;
        this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
      }

    });

    public ICommand MoveRightCommand => new RelayCommand(x => {
      if (this._scollMoverIdx == this.someobslist.Count - 1) {
        this._scollMoverIdx = 0;
        this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
      } else {
        _scollMoverIdx++;
        this._container.ScrollToCenterOfView(this.someobslist[_scollMoverIdx]);
      }
    });

Its not really pretty, but i wanted to keep it simple. The linked Extension method is greate for reusability (Credits to Ray Burns). If you want this to be MVVM-conform, i suggest making a CustomControl, since scrolling from ViewModel is breaking the pattern.

Cheers

Community
  • 1
  • 1
lokusking
  • 7,396
  • 13
  • 38
  • 57
  • I'm away from my work pc so i cant test it but all that looks like is the active tab being set by the repeat button. I'd like the ability to scroll the active tab into view if it isn't in view. – cool mr croc Aug 04 '16 at 20:32
  • 1
    Oh ok. I missunderstood that. Let Me fix that tomorrow – lokusking Aug 04 '16 at 20:33
  • this is for a stackpanel of headers within a tabcontrol, that extension method looks like its for listview. I'm also confused as to where that code goes, the stackpanel is specified in the tabcontrol template, I don't know if it's bound to a view controller. – cool mr croc Aug 05 '16 at 09:25
  • 1
    It doesnt really matter, where you put that extensionmethod. It works with your `TabControl` and the Edit in my Answer. Also use the commands i suggest before my edit. Works fine on my machine – lokusking Aug 05 '16 at 09:33
  • it won't compile the commands, at the lambda operator it complains it was expecting a semi colon. I called scrollintocenterofview elsewhere and it crashed at runtime due to the items control being null. – cool mr croc Aug 05 '16 at 10:48
  • sorry, I forgot the loaded event. I still can't compile the commands but I'm using the click event of a separate pair of buttons and something is happening. it's scrolling the stackpanel just not as intended. – cool mr croc Aug 05 '16 at 11:11
  • ok, just adjusted the code a little and got it working. I'd still like to have a little more control such as scrolling just enough to allow it to be viewed but now I have all this I'm fairly sure I can do that. thanks a lot. – cool mr croc Aug 05 '16 at 11:16