0
votes

I'm currently trying to display a Dictionary (which is held in a Dictionary itself).

I started at first using a UniformGrid as ItemsPanelTemplate, but realized pretty fast, the items to display can have individual heights.

I've got so far, that I can display all content using the UniformGrid, but can't seem to get it working using a Grid or StackPanel as ItemsPanelTemplate.

The code below is working fine with the downside that each Operation-block is given the same height though their height can be variable. After given some thought I came to the conclusion that a StackPanel would be best to use, as the Operations would be shown bleow each other taking the height they needed. But when I tried, I relaized they take only a fraction of the ListView's height.

Worth to mention: The Operation-UserControl in itself does evaluate its height and build its layout accordingly. So it doesn't take the space needed to display all content, but displays the content which does fit in the available space.

So how can I achieve that the ListViewItems (=operations) take the ListView's full height?

EDIT: clarification
if the described behaviour isn't possible with any above mentioned control, but any other could provide the needed funtionality, let me know...

EDIT2: some examples
Total available space: 500
No Scrollbar.
Sidenote: there is no maxItemLimit, but it's highly unlikely that the ItemCount would exceed 10.

Given 1 item: (needed space to display all content 300)
This single item would take 300.

Given 2 items: (these would need 150 and 200 of space)
Both items would be displayed in there full size: 150, 200.
(Presumably only working with a StackPanel.)

Given 10 items:
Those 10 would be squeezed equally or relative to full-desired size in the 500 (so 50 per item).
Both behaviours would be fine.

UniformGrid vs StackPanel

<UserControl x:Name="vDay" x:Class="RefServiceClient.Day"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:RefServiceClient"
        mc:Ignorable="d" 
        d:DesignHeight="60" d:DesignWidth="120"
        MinHeight="40">

<Grid x:Name="gridDay" 
      Width="{Binding ActualWidth, ElementName=vDay, Mode=OneWay}" 
      Height="{Binding ActualHeight, ElementName=vDay, Mode=OneWay}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <Grid x:Name="DayHeader" Grid.Row="0">
        <!--containing header info: several textboxes, which are irrelevant for the question-->

        <TextBox x:Name="dayShortname"
                 Grid.Row="0" Grid.Column="1"
                 VerticalAlignment="Center"
                 HorizontalAlignment="Stretch"
                 Margin="1"
                 Text="{Binding Path=Value.DayShortname}"/>
    </Grid>

    <ListView x:Name="operations" Grid.Row="1" Background="Aqua"
              ItemsSource="{Binding Path=Value.OperationList}"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch"
              HorizontalContentAlignment="Stretch"
              VerticalContentAlignment="Stretch"
              ScrollViewer.HorizontalScrollBarVisibility="Disabled"
              ScrollViewer.VerticalScrollBarVisibility="Disabled">

        <ListView.ItemTemplate>
            <DataTemplate>
                <local:Operation Background="Crimson" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch"/>
                <!--<local:Operation Background="Crimson" />-->
            </DataTemplate>
        </ListView.ItemTemplate>

        <ListView.ItemsPanel>
            <ItemsPanelTemplate>

                <!--<Grid Grid.IsSharedSizeScope="True"/>-->
                <!--<StackPanel/>-->
                <!--<VirtualizingStackPanel Orientation="Vertical"/>-->
                <UniformGrid Columns="1"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>

</Grid>

2
I think the problem is your local:Operation implementation. If it would demand an appropriate height, the ListView with StackPanel as itemspanel would give appropriate space for each list item. - grek40
@grek40 I can follow you there. But as the ListView can hold multiple local:Operation and the available total space stays the same, there is in my opinion only one solution: make the local:Operations show a minimum of content (header-data) and show detail-data if more space is available. Otherwise (if operation takes always the needed space) I wouldn't be able to display all Operations without a scrollbar. - Evaniar
Have you tried using a DataTemplate using a StackPanel instead of the UserControl? - XAMlMAX
You really have to clarify your desired behavior... if I understand you correctly, given 1 item and enough space, you would want the one item to take as much space as it needs. Given 100 items and 500 available height, you would like to squeeze 100 items in 500 height instead of using a scrollbar. Is there a limit to what you try to display? Should the 100 items be equal-sized when not enough space is available or should they be re-sized relative to their full desired size? - grek40
@XAMlMAX no, I haven't tried that yet. went only the dataTemplate route via the userControl. but I'll try that - Evaniar

2 Answers

0
votes

You could create a custom panel that arranges your item according to your rules. Then you just have to design your items in a way that they display nicely for whatever size they are allowed to take.

A rough sketch of the panel could look as follows:

public class SqueezeStackPanel : Panel
{
    protected override Size MeasureOverride(Size availableSize)
    {
        var desiredHeight = 0.0;
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            desiredHeight += child.DesiredSize.Height;
        }

        if (availableSize.Height < desiredHeight)
        {
            // we will never go out of bounds
            return availableSize;
        }
        return new Size(availableSize.Width, desiredHeight);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        // measure desired heights of children in case of unconstrained height
        var size = MeasureOverride(new Size(finalSize.Width, double.PositiveInfinity));

        var startHeight = 0.0;
        var squeezeFactor = 1.0;
        // adjust the desired item height to the available height
        if (finalSize.Height < size.Height)
        {
            squeezeFactor = finalSize.Height / size.Height;
        }

        foreach (UIElement child in InternalChildren)
        {
            var allowedHeight = child.DesiredSize.Height * squeezeFactor;
            var area = new Rect(new Point(0, startHeight), new Size(finalSize.Width, allowedHeight));
            child.Arrange(area);
            startHeight += allowedHeight;
        }

        return new Size(finalSize.Width, startHeight);
    }
}

This panel can be used in the ItemsPanelTemplate of your ListView with disabled scrollbars.

0
votes

It depends. I'll give you an options. First. Implement, let say, Boolean AttachedProperty, marking whether this particular instance should be of certain size. In case 0/1 is not sufficient, declare appropriate enumeration. Second. Extend existing StackPanel, override appropriate protected members. At least, MeasureOverride/ArrangeOverride. There you can read the value of corresponding attached property and decide how big or small it has to be. Does it sound like a solution? In case it does, I can provide some examples.