1
votes

I have a two-columns grid layout that contains two custom controls. The two controls together make a table/datagrid. The reason I've split this table/datagrid into two chunks is that the second control (the one on the right) could be horizontally very large, so it needs to be wrapped in a ScrollViewer. The one on the left acts as a header and should be visible at all times, it can't be scrolled out of view. The two parts have a matching height.

The problem, as you can see bellow, is that the horizontal scrollbar of the scrollviewer pushes the second part up instead of taking its own space.

enter image description here

Mind you, the ScrollViewer's vertical scrollbar is not used as the height of the table is relatively small.

Here is how it should look:

enter image description here

What I've tried so far:

  • I tried adding a row to the grid (both as auto and * heights), and made the ScrollViewer span over it but to no avail.
  • I've set that row's height to match the scrollbar height which kind of worked but I see two huge issues with this approach:
    1. If the scrollbar is not needed (the second control is not so big horizontally), that row becomes an empty space used for nothing, sort of a like a margin which is undesirable, in my case anyway.
    2. It's not reliable as it relies on a hardcoded size of the scrollbar which we know can change from environment to environment and from theme to theme.
3
SADLY there is "no" easy solution for this. If you want to have that behavior then you need to override original styles. Here you can see how all controls are styled in wpf. docs.microsoft.com/en-us/dotnet/framework/wpf/controls/… - Zer0
Here is an example how to make scrollbar overlay ypur background. github.com/angelsix/fasetto-word/blob/develop/Source/… - Zer0
Difficult to help w/o any bit of code. - Simon Mourier
There is no need to create two DataGrid's. Use can use FrozenColumnCount property of DataGrid to freeze the first column. - Aakanksha

3 Answers

6
votes

For that you only need a single datagrid.

Simply set the HorizontalScrollBarVisibility="Auto" and FrozenColumnCount="1".

enter image description here

3
votes

If the controls are separate you could just set the margin on the bottom of one container and not the other

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="400" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid Margin="0,0,0,18">
            <DataGrid>

            </DataGrid>
        </Grid>

        <ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Visible">
            <DataGrid>

        </DataGrid>
        </ScrollViewer>
    </Grid>
2
votes

Another simple solution will be to have 3 rows in the Grid and let the ScrollViewer.ScrollBar to extend on the 3rd row.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Button Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Add columns" Command="{Binding Path=AddCommand}" Height="25" Margin="10"/>

    <DataGrid x:Name="HeadersGrid"  Grid.Row="1" Grid.Column="0" ItemsSource="{Binding Path=HeadersCollection}"/>

    <ScrollViewer Grid.Row="1" Grid.Column="1" Grid.RowSpan="2" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
        <DataGrid x:Name="MyGrid" ItemsSource="{Binding Path=DataCollection}" Height="{Binding ElementName=HeadersGrid, Path=ActualHeight}"></DataGrid>
    </ScrollViewer>
</Grid>

In the above example I am binding the Height of the second DataGrid to the first DataGrid. When the ScrollBar of the ScrollViewer appears it will be shown on the 3rd row.

enter image description here