简体   繁体   中英

WPF DataGrid horizontal scrollbar not showing

I have created simple DataGrid with 4 columns, which go outside the bounds of DataGrid, and horizontal scrollbar is not showing. I tried setting width to each column but nothing changed. Here is my XAML:

<Window x:Class="WPFTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Grid>
        <DataGrid Height="200" Width="200" HorizontalScrollBarVisibility="Visible">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Column 1" />
                <DataGridTextColumn Header="Column 2" />
                <DataGridTextColumn Header="Column 3" />
                <DataGridTextColumn Header="Column 4" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

And here is what I get:

在此处输入图像描述

I have also tried wrapping DataGrid with ScrollViewer. Nothing. How can I make scrollbar appear?

I also very much dislike this behavior, since I use header filters. My "hack" is much easier than the above: simply place the data grid inside a new ScrollViewer with HorizontalScrollBarVisibility=Auto and VerticalScrollBarVisibility=Disabled (the DataGrid already handles that one fine). Like so:

<ScrollViewer HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Disabled">
    <DataGrid>
        ...
    </DataGrid>
</ScrollViewer>

Sure, it's more controls on the page, but a lot easier than the hacky code above. So far I haven't found a way to make the data grid do this automatically.

The side effect of this solution may be the vertical scrollbar hidden until you scroll to the right.

this was actually a major issue to me since I am creating many columns and allow the user to filter by having filter controls in the header.

When the user scrolls to the right and places a filter in a column and NO rows are returned because of these criteria then the entire grid would move to the left (all columns to the default left position) and the horizontal scrollbar would disappear so the user can't scroll to the filter column to undo his/her action!!

Major pain!

The 'hack' I have just placed in the code is a way around it: (the _dv pointing at a DataView from a DataTable)

// construct an overall sql filter statement
string sqlFilter = _setttings.SGColumns.GetFilterSQL();

BindingListCollectionView view = CollectionViewSource.GetDefaultView(gridMain.ItemsSource) as BindingListCollectionView;

if (view != null)
    view.CustomFilter = sqlFilter;      // "XGROUP = 'E' AND GEOG = 'U'";

if (view != null && _dv.Count == 0)
{
    gridMain.ItemsSource = null;
    gridMain.Items.Add("hello");
    _RowHeightTemp = gridMain.RowHeight;
    gridMain.RowHeight = 0;
}
else
{
    if (gridMain.Items.Count == 1 && gridMain.Items[0].ToString() == "hello")
    {
        gridMain.Items.Clear();
        gridMain.ItemsSource = _dv;
        view = CollectionViewSource.GetDefaultView(gridMain.ItemsSource) as BindingListCollectionView;
        view.CustomFilter = sqlFilter;
        gridMain.RowHeight = _RowHeightTemp;
    }
}

This now ensures that the grid stays in its exact position when the no rows are displayed!

I think that when the Datagrid is empty, the ScrollViewer doesn't handle anything. Try to fill the columns by adding an ItemsSource , the scrolling should therefore appear :)

The scrolling will work automatically as soon as you add some data to the grid. To test you can apply this code

Name your grid to "grid"

Attached the Window Loaded event

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        grid.Items.Add(new object());
    }

You will see the scrolling appears.

Although the question is an old one, I have thought that it might help someone. Based on lauren's answer:

<ScrollViewer VerticalScrollBarVisibility="Disabled">
    <DataGrid x:Name="ScrollDataGrid"
        HorizontalScrollBarVisibility="Auto"
        VerticalScrollBarVisibility="Auto" ... >
    </DataGrid>
    <ScrollViewer.Style>
        <Style BasedOn="{StaticResource {x:Type ScrollViewer}}" TargetType="ScrollViewer">
            <Setter Property="HorizontalScrollBarVisibility" Value="Disabled" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=ScrollDataGrid, Path=Items.Count}" Value="0">
                    <Setter Property="HorizontalScrollBarVisibility" Value="Auto" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ScrollViewer.Style>
</ScrollViewer>

If the DataGrid have records, the ScrollViewer doesn't show the scroll bars and uses the scroll bars of the DataGrid.

Set Datagrid 's properties as CanUserAddRows="True" IsReadOnly="True" and wrap it with ScrollViewer. CanUserAddRows gives you an empty row. Empty row retains scrollbar. IsReadOnly hides the empty row since it's readonly.

Downside is, when you scroll vertically datagrid headers would be hidden.

Obviously you need horizontal scroll bar.

Two things need to do:

1. Add property IsReadOnly="True" to your DataGrid

2. Add MaxWidth="1200" VerticalScrollBarVisibility="Auto" to your ScrollViewer

MaxWidth need to be set, you can change 1200 to any other value as you need.

<ScrollViewer MaxWidth="1200" VerticalScrollBarVisibility="Auto">
    <DataGrid IsReadOnly="True">

    </DataGrid>
</ScrollViewer>

This works for me

<ScrollViewer  ScrollViewer.HorizontalScrollBarVisibility="Auto"  Width="auto">
    <DataGrid></DataGrid>
</ScrollViewer>

The horizontal scroll bar is displayed only if the sum of the column widths exceeds the available width. The simplest approach is to ask WPF to adjust the width of the columns to their content with Width="SizeToCells" .

Based on Marcel answer I made this version

Window resources:

<CollectionViewSource x:Key="NormalCollectionView" Source="{Binding Items}" Filter="CollectionViewSource_Filter"/>
<CollectionViewSource x:Key="EmptyCollectionView"/>

Datagrid style:

<DataGrid.Style>
  <Style TargetType="DataGrid">
    <Style.Triggers>
      <DataTrigger Binding="{Binding IsEmpty, Source={StaticResource NormalCollectionView}}" Value="True">
        <Setter Property="ItemsSource" Value="{Binding Source={StaticResource EmptyCollectionView}}"/>
        <Setter Property="RowHeight" Value="0"/>
      </DataTrigger>
      <DataTrigger Binding="{Binding IsEmpty, Source={StaticResource NormalCollectionView}}" Value="False">
        <Setter Property="ItemsSource" Value="{Binding Source={StaticResource NormalCollectionView}}"/>
      </DataTrigger>
    </Style.Triggers>
  </Style>
</DataGrid.Style>
public MyWindow()
{
  InitializeComponent();
  var emptyCollectionView = Resources["EmptyCollectionView"] as CollectionViewSource;
  emptyCollectionView.Source = new ObservableCollection<MyDataType>
  {
    new MyDataType()
  };
  emptyCollectionView.View.Refresh();
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
  var datacontext = DataContext as MyDataContextType;
  e.Accepted = datacontext.CheckFilterForLine(e.Item as MyDataType);
}
  • emptyCollectionView.View.Refresh(); may not be necessary
  • There may be a better way to initialize the "empty" collection in the xaml

I did it that way because I have frozen columns that I thought would not work wrapped with a ScrollViewer. I liked Marcel's answer but did not want to deal with the manual grid items management and at some point trying to implement it, it became spaghetti because of all the events.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM