1

I have a DataGrid in a ScrollViewer. I have one of two problems:

  1. When the width is shrunk and the item text is cut off (the H2 column isn't wide enough), the scroll bar doesn't appear. However, the two columns that I have are sized appropriately and can't be resized off-screen. The XAML is (basically):

    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <DataGrid Width="{Binding ActualWidth, 
                      RelativeSource={RelativeSource AncestorType={x:Type ScrollViewer}}}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="H1" Width="40" MinWidth="35"/>
                <DataGridTextColumn Header="H2" Width="*" MinWidth="47"/>
            </DataGrid.Columns>
        </DataGrid>
    </ScrollViewer>
    
  2. When I have a working scrollbar, the columns can be resized so that the right one can be out of view (the center divider can be moved far enough right that the entire column is out of view). XAML:

    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Grid>
            <DataGrid Width="{Binding ActualWidth, 
                          RelativeSource={RelativeSource AncestorType={x:Type Grid}}}">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="H1" Width="40" MinWidth="35"/>
                    <DataGridTextColumn Header="H2" Width="*" MinWidth="47"/>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </ScrollViewer>
    

(Note: in both cases, I have excluded the itemsource as I don't believe it is necessary for the question, I can add that, as well as the backend code, if needed).

I imagine that this has to do with the element that the DataGrid is bound to (maybe the Grid element doesn't resize appropriately, I have tried binding the width of the Grid to the ScrollViewer but the problem is the same as (1)). I have also noticed that the scroll bar does appear (both instances) when the vertical content is cut off and the vertical scroll bar appears (both appear at the same time). Any suggestions to have the scrollbar and ability to ensure that the columns doesn't go off-screen?

7
  • 1
    Why not use the datagrid's built in horizontalscrollbar? Commented Jan 17, 2019 at 16:32
  • Same issue as (1) Commented Jan 17, 2019 at 16:35
  • Why shouldn't the columns go off-screen? You can use the scrollbar to reach them. Or vice versa, why the scrollbar if all columns should remain on screen? Commented Jan 25, 2019 at 17:27
  • @Funk, I'd like for the user to be able to see all (both) columns at all time and be able to scroll if the content in the columns goes off screen Commented Jan 25, 2019 at 17:42
  • So, you want the all-columns-in-sight behavior both when resizing the container (window) and resizing the columns? Does that mean resizing should be stopped when the last column is about to go out of sight? Commented Jan 25, 2019 at 17:52

2 Answers 2

1

The problem is that the width of the DataGrid is bound to the width of the ScrollViewer

<DataGrid Width={Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type Grid}}}">

The DataGrid is never going to be wider than the ScrollViewer so the scrollbar will not be enabled.

Setting HorizontalAlignment to 'Stretch' will achieve the layout that I think you are looking for and allow scrolling. So the DataGrid element ought to be:

 <DataGrid HorizontalAlignment="Stretch">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="H1" Width="40" MinWidth="35"/>
                    <DataGridTextColumn Header="H2" Width="*" MinWidth="47"/>
                </DataGrid.Columns>
            </DataGrid>
Sign up to request clarification or add additional context in comments.

1 Comment

Unfortunately, that didn't do anything
1
+50

Here's what I came up with by making use of VisualTreeHelper.

Create a method that can search the Visual Tree for a child of a particular type. I found a method for looking for a parent (the reverse direction) that I was able to modify. https://stackoverflow.com/a/636456/1640271.

public static T FindVisualChild<T>(DependencyObject parent)
    where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        DependencyObject childObject = VisualTreeHelper.GetChild(parent, i);

        if (childObject == null) return null;

        if (childObject is T obj)
        {
            return obj;
        }
        else
        {
            return FindVisualChild<T>(childObject);
        }
    }

    return null;
}

My code behind included creating one constant, one class variable, and using two Window event triggers.

Constant

(imposes a constraint on the Window width to ensure that at least some portion of the second columns can always be seen).

private const double _item2MinViewableWidth = 100;

Variable

(used to capture the Grid from the Visual Tree that is inside the ScrollView of the DataGrid).

private Grid _innerGrid;

Events

private void Window_ContentRendered(object sender, EventArgs e)
{
    _innerGrid = UIHelper.FindVisualChild<Grid>(dataGrid);

    item2Column.MinWidth = _item2MinViewableWidth;

    item1Column.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
    item2Column.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);

    MaxWidth = ActualWidth;

    _innerGrid.MinWidth = item1Column.ActualWidth + _item2MinViewableWidth;
    _innerGrid.Width = item1Column.ActualWidth + _item2MinViewableWidth;

    UpdateLayout();

    var mainGridInitWidth = mainGrid.ActualWidth;
    MinWidth = ActualWidth;
    _innerGrid.Width = Double.NaN;

    mainGrid.Width = mainGridInitWidth;
}

private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (e.WidthChanged && _innerGrid != null)
    {
        var widthDetla = e.NewSize.Width - e.PreviousSize.Width;
        mainGrid.Width += widthDetla;
    }

    if (Math.Abs(ActualWidth - MaxWidth) < 1)
    {
        dataGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
    }
    else
    {
        dataGrid.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
    }
}

Here's my XAML for good measure:

<Window
x:Class="WPFSandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFSandbox"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Height="450"
ContentRendered="Window_ContentRendered"
ResizeMode="CanResize"
SizeChanged="Window_SizeChanged"
SizeToContent="Width">

<Grid x:Name="mainGrid">
    <DataGrid x:Name="dataGrid"
        AutoGenerateColumns="False"
        CanUserResizeColumns="False"
        HeadersVisibility="Column"
        IsReadOnly="True"
        ItemsSource="{Binding MyItems}">
        <DataGrid.ColumnHeaderStyle>
            <Style TargetType="{x:Type DataGridColumnHeader}">
                <Setter
                    Property="SeparatorVisibility"
                    Value="Hidden" />
            </Style>
        </DataGrid.ColumnHeaderStyle>
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="item1Column"
                Binding="{Binding Item1}"
                Header="Item1" />
            <DataGridTextColumn x:Name="item2Column"
                Binding="{Binding Item2}"
                Header="Item2" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

Hopefully, this is in line with what you need.

18 Comments

This seems like the answer. The only issue occurs if the header is longer than any of the data. Once I figure that out, the issue will be solved.
I think you can use DataGridLength(1, DataGridLengthUnitType.SizeToHeader) to figure out the width for the header. You can use this result as a third component in determining your minimum widths.
Actually, just noticed that it gives option to increase (to the right) the column off-screen.
@Greg Can you be more specific so I can be helpful? Is this not the behavior you desired? Is the issue that the second column can be widened to exist beyond the viewable area? Perhaps you could update your question with some visual aids to facilitate your description of the activity you need and how it is distinguished from my suggested solution? From your written description, I get the sense that i'm missing a nuance; i just can't pinpoint what it is.
"Is the issue that the second column can be widened to exist beyond the viewable area?" Yes, with your solution, that is the (I believe only) issue I have. Ideally, the user wouldn't be able to resize the columns so that they disappear from view.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.