Reputation: 14992
I have a TabControl
, which has a TabPanel
, which is put inside a ScrollViewer
.
<Style x:Key="TabCtrl" TargetType="{x:Type TabControl}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Padding" Value="2,0,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<RepeatButton
x:Name="ScrolltoLeft_Btn"
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Top"
Command="{x:Static ScrollBar.LineLeftCommand}"
CommandTarget="{Binding ElementName=sv}"
Style="{StaticResource ScrolltoLeft}" />
<ScrollViewer
x:Name="sv"
Grid.Row="0"
Grid.Column="1"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled">
<TabPanel
x:Name="HeaderPanel"
Panel.ZIndex="1"
IsItemsHost="true"
KeyboardNavigation.TabIndex="1" />
</ScrollViewer>
<ContentPresenter
x:Name="PART_SelectedContentHost"
Grid.Row="1"
Grid.ColumnSpan="2"
Grid.Column="0"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<RepeatButton
x:Name="ScrolltoRight_Btn"
Grid.Row="0"
Grid.Column="2"
VerticalAlignment="Top"
Command="{x:Static ScrollBar.LineRightCommand}"
CommandTarget="{Binding ElementName=sv}"
Style="{StaticResource ScrolltoRight}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When I press the repeat buttons, the amount which is scrolled is minimal, a small portion of the width of one TabItem
.
I want this to be bigger. I want (at a minimal) to scroll the width of TabItem
.
I already played with the CanContentScroll
property of a ScrollViewer
, but that doesn't change anything.
I also tried to change the SmallChange
property on the horizontal scrollbar, but that also has no impact.
myTab.ApplyTemplate();
var scrollviewer = myTab.Template.FindName("sv", myTab) as ScrollViewer;
if (scrollviewer != null)
{
scrollviewer.ApplyTemplate();
_scrollBar = scrollviewer.Template.FindName("PART_HorizontalScrollBar", scrollviewer) as ScrollBar;
if (_scrollBar != null)
{
_scrollBar.SmallChange = 0.5;
}
}
Upvotes: 0
Views: 1594
Reputation: 15227
The SmallChange
property of a WPF ScrollBar
is only considered for scrolling when the scroll bar is stand-alone (that means, not in a ScrollViewer
). Since you are using a ScrollViewer
in your control template, this will never work. A ScrollViewer
will always apply a default small change of 16 units.
You have two options now:
IScrollInfo
in a wrapper class (e.g. derived from a ContentControl
), attach it to the scroll viewer as content, put the TabPanel
inside of this customized wrapper class, set the CanContentScroll
property of the ScrollViewer
to true
. Now you have full control of the scrolling.ScrollBar
and let it scroll the ScrollViewer
. I show you the second approach:
Below your ScrollViewer
, add a new scroll bar:
<ScrollBar
x:Name="myScrollBar"
Grid.Row="0" Grid.Column="1" Orientation="Horizontal"
Visibility="Collapsed"
Tag="{Binding ElementName=sv}"
Minimum="0"
Maximum="{Binding ScrollableWidth, ElementName=sv}"
ViewportSize="{Binding ViewportWidth, ElementName=sv}"
Value="{Binding HorizontalOffset, ElementName=sv, Mode=OneWay}"
SmallChange="100"
Scroll="MyScrollBar_OnScroll"/>
You can change the SmallChange
property as you wish.
Update both scroll commands to target this scroll bar, not the ScrollViewer
:
<RepeatButton
<!-- ... -->
CommandTarget="{Binding ElementName=myScrollBar}"/>
Finally, you need to connect the external scroll bar to the ScrollViewer
:
void MyScrollBar_OnScroll(object sender, ScrollEventArgs e)
{
ScrollBar sb = (ScrollBar)sender;
(sb.Tag as ScrollViewer)?.ScrollToHorizontalOffset(e.NewValue);
}
(You might want to make a Behavior
out of this to keep the code-behind empty, to avoid using the Tag
property, and to allow reusability).
Upvotes: 2