Dan Champagne
Dan Champagne

Reputation: 920

A WPF ItemsControl and WrapPanel walk into a bar

I have a ItemsControl that displays a bunch of UserControl's inside of a WrapPanel. This works perfectly, unless I have a bunch of UserControls, and then the overflow is rendered off screen, and I can't access it. My goal is to have the WrapPanel wrap horizontally, but once the controls are off the screen, to present a scroll bar, and this seems to not work for me.

<ItemsControl ItemsSource="{Binding Servers, Mode=OneWay}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1" Margin="5,5,5,5">
                <local:ServerControl DataContext="{Binding }" /> <!-- The actual UserControl -->
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

When the application first starts, this is what it looks like. What you can't see if that there should be 14 boxes viewed. The WrapPanel is doing its job, but it's rendered outside of the bounds of the window.

User Controls off the screen

This shows all the UserControls, but I had to expand the window to be able to see them all.

Expanded window to see all controls, rather than a scrollbar

Any help would be greatly appreciated.

Full XAML:

<Window x:Class="ServerMonitor.Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ServerMonitor.Wpf"
        xmlns:models="clr-namespace:ServerMonitor.Wpf.Models"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        Title="Leading Hedge Server Monitor" Height="350" Width="800">
    <Window.DataContext>
        <models:MainWindowViewModel>
            <models:MainWindowViewModel.MachineNames>
                <!-- Test Servers -->
                <System:String>T009</System:String>
                <System:String>T010</System:String>
                <System:String>T011</System:String>
                <System:String>T012</System:String>
            </models:MainWindowViewModel.MachineNames>
        </models:MainWindowViewModel>
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Menu Grid.Row="0">

        </Menu>

        <ItemsControl Grid.Row="1" ItemsSource="{Binding Servers, Mode=OneWay}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="1" Margin="5,5,5,5">
                        <local:ServerControl DataContext="{Binding }" />
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.Template>
                <ControlTemplate TargetType="{x:Type ItemsControl}">
                    <ScrollViewer VerticalScrollBarVisibility="Auto">
                        <ItemsPresenter />
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>
        </ItemsControl>

    </Grid>
</Window>

Upvotes: 2

Views: 3940

Answers (2)

Laith
Laith

Reputation: 6091

Change you second row height to *

<Grid.RowDefinitions>
   <RowDefinition Height="Auto" />
   <RowDefinition Height="*" /> <-- This is what you want -->
   <RowDefinition Height="Auto" />
   <RowDefinition Height="Auto" />
</Grid.RowDefinitions>

Setting a RowDefinition to Auto means it will calculate the cumulative DesiredHeight of all child elements in that row and assign it to the Height property of RowDefinition. So, as your WrapPanel grows, it will apply the height to that row and stretch out your parent Grid.

Upvotes: 2

<ItemsControl ItemsSource="{Binding Servers, Mode=OneWay}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1" Margin="5,5,5,5">
                <local:ServerControl DataContext="{Binding }" /> <!-- The actual UserControl -->
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Template>
        <ControlTemplate TargetType="{x:Type ItemsControl}">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <ItemsPresenter />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

OR

<ScrollViewer VerticalScrollBarVisibility="Auto">
  <ItemsControl ItemsSource="{Binding Servers, Mode=OneWay}">
     ...
  <ItemsControl/>
</ScrollViewer>

Upvotes: 8

Related Questions