Home > Enterprise >  How can I make this scrollviewer in the grid cell work both horizontaly and verticaly?
How can I make this scrollviewer in the grid cell work both horizontaly and verticaly?

Time:01-26

I have a grid with some data and one of the cells contains rather long strings (and there could be quite a few). So to not use too much of the available window space, I'd like those strings to be scrollable. Vertically works, but whatever I try, I can't get a horizontal scrollbar.

This is my xaml:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"           
        Title="MainWindow" Height="150" Width="250">
    <Grid>
        <Grid.ColumnDefinitions>  
            <ColumnDefinition Width="200"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>    
            <RowDefinition Height="100"/>
        </Grid.RowDefinitions>           
        <ScrollViewer Grid.Row="0" Grid.Column="0">
            <ItemsControl  ItemsSource="{Binding Path=BoundTexts}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Text}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Vertical"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
</Window>

and here's the code behind to test.

using System.Collections.Generic;
using System.Windows; 

namespace WpfApp1

{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            List<BoundClass> temp = new List<BoundClass>();
            for (int i = 0; i < 10; i  )
            {
                string t = ""; // just to create some long strings.
                for (int j = 0; j < 10; j  ) // I know it can be done better.
                {
                    t  = $"{j*10:D2}********";
                }               
                temp.Add(new BoundClass(t));
            }
            BoundTexts = temp.ToArray();
            DataContext = this;
        }       

        public BoundClass[] BoundTexts { get; set; }
    } 

    public class BoundClass
    {
        public string Text { get; set;}
        public BoundClass(string text)
        {
            Text = text;
        }
    }
}

I know there are a few similar questions on here, but as far as I have seen, they are all shrouded in templates and other complex topics. Also some are answered by "make sure you have a restraining container around it", I think I do by the grid.

CodePudding user response:

Setting ScrollViewer.HorizontalScrollBarVisibility and ScrollViewer.VerticalScrollBarVisibility to "Auto" should do the trick.

Default value for VerticalScrollBarVisibility is ScrollBarVisibility.Visible BUT for HorizontalScrollBarVisibility is ScrollBarVisibility.Disabled. So it should be even enough to set only HorizontalScrollBarVisibility = "Auto"

<ScrollViewer Grid.Row="0" Grid.Column="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">

CodePudding user response:

The proper way to add a ScrollViewer to an ItemsControl is to put it into the ControlTemplate to wrap the ItemsPresenter. This way the ScrollViewer behaves correctly.

If you don't do it this way (and instead wrap the ItemsControl) the ScrollViewer will try to scroll the ItemsControl and not the items!
But you want the ScrollViewer to detect when items of the ItemsControl overflow. Naturally, the ItemsControl itself will stretch to occupy the available space - it won't overflow and will be displayed correctly (fully visible). But the items do overflow the space of the ItemsControl. That's why wrapping the ItemsControl won't work as expected.

Additionally, you must explicitly enable the ScrollViewer.HorizontalScrollBarVisibility. It's important to know that setting it to Auto will impact the performance. It's recommended to set it to Hidden or Visible.

<ItemsControl Height="200">
  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <ScrollViewer CanContentScroll="True"
                    HorizontalScrollBarVisibility="Visible"
                    VerticalScrollBarVisibility="Visible">
        <ItemsPresenter />
      </ScrollViewer>
    </ControlTemplate>
  </ItemsControl.Template>

  <!-- Consider to enable virtualization by adding a VirtualizingStackPanel as host Panel.
       Important: don't forget to set ScrollViewer.CanContentScroll to 'True' -->
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <VirtualizingStackPanel />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
</ItemsControl>
  • Related