Search code examples
wpfwindowscrollbarstackpanel

WPF controls in StackPanels not getting scroll bar


I have the following window setup:

<Window x:Class="SearchWindow"
    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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:POR"
    mc:Ignorable="d"
    Title="SearchWindow"
    Height="450" 
    Width="1000"
    Loaded="Window_Loaded"
    ResizeMode="NoResize" 
    Icon="/Images/receipt.ico" 
    WindowStartupLocation="CenterScreen">
<Grid>
    <StackPanel Orientation="Vertical">
        <!-- Search Box -->
        <StackPanel x:Name="SP_SearchBox" Margin="0,5,0,0" 
                        DockPanel.Dock="Top" Orientation="Horizontal" HorizontalAlignment="Center">
            <Border CornerRadius="6"
                        BorderBrush="Gray"
                        BorderThickness="2"
                        Padding="1">
                <StackPanel Orientation="Horizontal">
                    <Image Source="\Images\magnify.png" Height="21" VerticalAlignment="Center"/>
                    <TextBox x:Name="TB_search"    
                                 Width="220"  
                                 FontSize="12"    
                                 BorderThickness="0"  
                                 VerticalAlignment="Center"
                                 HorizontalContentAlignment="left"    
                                 Padding="0,0,0,0"
                                 Text="Search..."
                                 Background="Transparent"    
                                 Foreground="Gray"    
                                 TextChanged="TB_Search_TextChanged"
                                 PreviewKeyUp="TB_search_PreviewKeyUp"/>
                    <Image x:Name="BTN_Clear" Source="\Images\close.png" Height="20" 
                               VerticalAlignment="Center" Visibility="Visible" Cursor="Hand" 
                               MouseLeftButtonUp="BTN_Clear_MouseLeftButtonUp"/>
                </StackPanel>
            </Border>
        </StackPanel>
        <!-- Auto Suggestion box -->
        <Popup x:Name="Popup" IsOpen="False" PlacementTarget="{Binding ElementName=SP_SearchBox}"
                   AllowsTransparency="True" PopupAnimation="Slide" Width="263" HorizontalOffset="-2" VerticalOffset="-2">
            <Border CornerRadius="6"
                    BorderBrush="Gray"
                    BorderThickness="1"
                    Padding="1">
                <ListView x:Name="LV_hints" Visibility="Visible" BorderThickness="0"
                         SelectionChanged="LV_hints_SelectionChanged"/>
            </Border>
        </Popup>
        <!-- Grid 1 -->
        <StackPanel Orientation="Vertical">
            <DataGrid x:Name="DG_Orders" ItemsSource="{Binding}"
                      Margin="6" VerticalContentAlignment="Center" Visibility="Hidden">
                <DataGrid.Columns>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button  Click="BTN_ShowItems_Click"
                                            Margin="3">Show Items</Button>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
            <!-- Grid 2 -->
            <DataGrid x:Name="DG_OrderItems" ItemsSource="{Binding}"
                      Margin="6" VerticalContentAlignment="Center" Visibility="Hidden">
                <DataGrid.Columns>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <Button x:Name="BTN_Receipt" Click="BTN_Receipt_Click"
                                            Margin="3">Receipt</Button>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </StackPanel>
</Grid>

I cannot figure out why am I not getting a scroll bar when the bottom DataGrid has more data and appears off the window at the bottom of it.

I've tried using <DockPanel> in various places, like the top-most <StackPanel> but that still did not show me any scroll bars. I have read that using controls such as <DockPanel> or <StackPanel> should automatically give me a scrollbar when the content does not fit on the window, but in my case it just goes off screen.

I have also tried using <Grid.ColumnDefinitions> and <Grid.RowDefinitions> and having a row and a column on the sides as well as top and bottom for 5px margin for the content, but again, the bottom DataGrid just expands down and cuts off on the window.

Thanks in advance!


Solution

  • The DataGrid needs a height constraint otherwise it will stretch to infinite. If the layout is defined correctly, the DataGrid will provide its own ScrollViewer (same applies to other ItemsControl classes like ListBox and ListView).
    Panels in general, like Grid, DockPanel, Canvas or StackPanel, don't have their own ScrollViewer. They need to be hosted by a ScrollViewer explicitly.

    You can define this constraint either by hosting it inside a Grid or by explicitly setting the Height property.

    For complex layout arrangements and advanced resize behavior, you should always prefer to use a Grid as root panel. At least you should know the different resize behavior. In your case, the StackPanel is not the proper root panel to layout the page.

    The following example creates a similar layout by utilizing the Grid as a content host. Instead of a vertically oriented StackPanel it uses a Grid that defines rows.
    The example shows how to provide a height constraint by setting an explicit height for the DataGrid (for the first DataGrid) and by using the implicit height that is calculated by the parent Grid (for the second DataGrid).

    The first DataGrid is located in the second row. The height constraint is locally set by setting DataGrid.Height.

    The second DataGrid is located in the third row, which is set to *: it will stretch to occupy the remaining height of the parent (the Grid, where Grid.Height is dictated by Window.Height).
    Because the Height returned by the third row evaluates to an actual value, the contained DataGrid.Height will automatically adapt to this value.

    For both DataGrid elements, due to the height constraint, the overflowing of rows will result in the scroll bars being displayed.

    <Window>
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition />
        </Grid.RowDefinitions>
    
        <!-- Search Box -->
        <StackPanel x:Name="SP_SearchBox"
                  Grid.Row="0" />
    
        <!-- Auto Suggestion box -->
        <Popup x:Name="Popup" />
    
        <!-- Grid 1 uses explicit height -->
        <DataGrid x:Name="DG_Orders"
                  Grid.Row="1"
                  Height="250" />
    
        <!-- Grid 2 uses implicit height -->
        <DataGrid x:Name="DG_OrderItems"
                  Grid.Row="2" />
      </Grid>
    </Window>