Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertical scrollbar includes header of ListView in WPF

Tags:

listview

wpf

I have a listview which is binded to source. It is working fine. I have set ScrollViewer.VerticalScrollBarVisibility="Auto", so that if there is no space to show the items, it should display the scroll bar.

Upto this it is working fine. It is showing the vertical scroll bar, but it is including the header of GridViewColoumn also. It is looking odd.

So how to show the vertical scrollbar only for the contents, not with header?

Any idea will be helpful.

like image 241
Syed Avatar asked Dec 28 '11 09:12

Syed


2 Answers

Try this...

        <ListView.Resources>
            <Style TargetType="{x:Type ScrollBar}"
                   BasedOn="{StaticResource {x:Type ScrollBar}}">
                <Style.Triggers>
                    <Trigger Property="Name" Value="PART_VerticalScrollBar">
                        <Setter Property="Margin" Value="0,18,0,0"/>
                    </Trigger>
                </Style.Triggers>                   
            </Style>
        </ListView.Resources>

EDIT:

To understand how this works first you will have to refer this msdn article that gives you the default template of the list view ... http://www.google.co.in/url?q=http://msdn.microsoft.com/en-us/library/ms788747(v%3Dvs.85).aspx&sa=U&ei=r_L6TuXlJ8XyrQep_anODw&ved=0CBQQFjAC&sig2=HNWppacyWyhYxn2NcUSbEw&usg=AFQjCNHzlst2jA_pMTzZsUGNxtbWBqYQLQ

In this template we have the verticle scroll bar defined with name PART_VerticalScrollBar.

Now if you want to change its properties such as Margin, you will have to set a default target type style for the scroll bar. In our example above, the targetType of the style is Scrollbar class but it has no resource Key! This means all scroll bars under that ListView will acquire the style and set their top margin to 18px. But we dont want it to apply to all scroll bars so I added a trigger that only targets this style to scrollbar with name "PART_VerticalScrollBar".

Let me know if this helps.

like image 177
WPF-it Avatar answered Nov 15 '22 11:11

WPF-it


I would achieve this by overriding the style for the ScrollViewer. The benefit of this is that it handles header resizing automatically.

XAML:

<Grid>
  <Grid.Resources>
    <local:HeightToMarginConverter x:Key="HeightToMarginConverter"/>
    <Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="{x:Type ScrollViewer}">
        <Setter Property="Focusable" Value="false"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                    <Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
<!-- Here I set Grid.ColumnSpan to 2, so it stretches over the scrollbar -->
                        <DockPanel Margin="{TemplateBinding Padding}" Grid.ColumnSpan="2">
                            <ScrollViewer DockPanel.Dock="Top" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
                                <GridViewHeaderRowPresenter x:Name="gridViewHeaderRowPresenter" AllowsColumnReorder="{Binding TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContainerStyle="{Binding TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderToolTip="{Binding TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderStringFormat="{Binding TemplatedParent.View.ColumnHeaderStringFormat, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContextMenu="{Binding TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplate="{Binding TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" Columns="{Binding TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplateSelector="{Binding TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}" Margin="2,0,2,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </ScrollViewer>
                            <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" KeyboardNavigation.DirectionalNavigation="Local" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </DockPanel>
                        <ScrollBar x:Name="PART_HorizontalScrollBar" Cursor="Arrow" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0.0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
<!-- Here I set the vertical scrollbar's top margin by binding it to the GridViewHeaderRowPresenter's ActualHeight property and using a converter -->
                        <ScrollBar x:Name="PART_VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0.0" Orientation="Vertical" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}" Margin="{Binding ActualHeight, ElementName=gridViewHeaderRowPresenter, Converter={StaticResource HeightToMarginConverter}}"/>
                        <DockPanel Background="{Binding Background, ElementName=PART_VerticalScrollBar}" Grid.Column="1" LastChildFill="false" Grid.Row="1">
                            <Rectangle DockPanel.Dock="Left" Fill="White" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Width="1"/>
                            <Rectangle DockPanel.Dock="Top" Fill="White" Height="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                        </DockPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
  </Grid.Resources>
  <ListView>
    <!-- Normal stuff here -->
  </ListView>
</Grid>

HeightToMarginConverter.cs:

class HeightToMarginConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? new Thickness() : new Thickness(0, (double)value, 0, 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}
like image 22
snurre Avatar answered Nov 15 '22 10:11

snurre