2
votes

I have a GroupBox (containing a ListBox) and an Expander, each in their own respective row within a Grid:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition  />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>


        <GroupBox Grid.Row="0" Header="My List">
            <ListBox>
                ...
            </ListBox>
        </GroupBox>


        <Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
            <Expander.Header>
                <TextBlock FontWeight="Bold">My Expander</TextBlock>
            </Expander.Header>

            <StackPanel Margin="5 5 5 5">
                <TextBlock TextWrapping="Wrap">
                    Lots<LineBreak />
                    and<LineBreak />
                    lots<LineBreak />
                    of<LineBreak />
                    lines.
                </TextBlock>
                <TextBlock TextWrapping="Wrap">
                    More <Run FontFamiliy="Courier">Stuff</Run> here.
                </TextBlock>
            </StackPanel>
        </Expander>
    <Grid>

Wanted behaviors:

I want the GroupBox (with the ListBox) to use all the available space for the Grid as defined by the parent (the parent being a Window for example) minus the size of the (closed) Expander. If the user opens up the Expander, it should let the GroupBox shrink (even collapse completely) and give space for the Expander.

However, I want to limit the height of the Expander to the maximum available height that the Grid is allowed to expand without causing overflows. If the Expander will therefore be limited in its height, it should start showing a vertical scrollbar.

Current behavior:

With my current XAML code, the Expander will make the Grid overflow, i.e. it will expand beyond the available space (and will therefore also not show a vertical scrollbar.)

Question in a nutshell:

How do I have to setup the Grid so that the Expander will be limited in its height to the maximum available height of the Grid?

2

2 Answers

2
votes

1st Solution: The simple solution I can think of is to have a readonly TextBox in place of Expander->TextBlock & have VerticalScrollBarVisibility= Auto Here is the sample code;

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition  />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <GroupBox Grid.Row="0" Header="My List">
        <ListBox>
            ...
        </ListBox>
    </GroupBox>


    <Expander Grid.Row="1" ScrollViewer.CanContentScroll="True">
        <Expander.Header>
            <TextBlock FontWeight="Bold">My Expander</TextBlock>
        </Expander.Header>

        <StackPanel Margin="5 5 5 5">
            <TextBox TextWrapping="Wrap" Margin="0,0,0,30"  MaxHeight="290" HorizontalAlignment="Left" VerticalScrollBarVisibility="Auto" IsReadOnly="True" >
                <TextBox.Text>
                    Lorem ipsum dolor sit amet...
                    Very Very long text

                </TextBox.Text>
            </TextBox>
        </StackPanel>
    </Expander>
    </Grid>

The only thing you will have to take care is MaxHeight of TextBox. MaxHeight should will be (window height - Expander height).

2nd Solution: If TextBlock usage is must you can wrap a scrollViewer around TextBlock and set its MaxHeight to (window height - Expander height)

Firstly:Add a reference to you XAML Window

xmlns:local="cld-namespace:AutoSizing"

Second: Create an instance of converter like this.

<Window.Resources>
    <local:SizeModifierConverter x:Key="SizeModifierConverter"/>
</Window.Resources>

Third: Use the Binding and Covnverter in the ScrollViewer

       <ScrollViewer VerticalScrollBarVisibility="Auto" 
                      MaxHeight="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window},
                      Converter={StaticResource SizeModifierConverter}, ConverterParameter= -50}" >
            <StackPanel Margin="5 5 5 5">
                    <TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20"  HorizontalAlignment="Left" >
                       Long text with Run Linereak and hyperlinks...
                    </TextBlock>

                    <TextBlock TextWrapping="Wrap" Margin="0,0,0,30" Width="20"  HorizontalAlignment="Left" >
                       Long text with Run Linereak and hyperlinks...
                    </TextBlock>
            </StackPanel>
        </ScrollViewer>

Converter will look like this;

public class SizeModifierConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double ActualWidth;
        if(double.TryParse(value.ToString(), out ActualWidth))
        {
            double AdjustValue = 0;
            if (double.TryParse(parameter.ToString(), out AdjustValue))
            {
                return (ActualWidth + AdjustValue);
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }
}

Hope this will be helpful!

1
votes

I came up with a solution that does not require any code-behind. My solution uses a DockPanel:

    <DockPanel>
        <Expander DockPanel.Dock="Bottom">
            <Expander.Header>
                <TextBlock FontWeight="Bold">My Expander</TextBlock>
            </Expander.Header>

            <ScrollViewer>
                <StackPanel Margin="5 5 5 5">
                    <TextBlock TextWrapping="Wrap">
                        Lots<LineBreak />
                        and<LineBreak />
                        lots<LineBreak />
                        of<LineBreak />
                        lines.
                    </TextBlock>
                    <TextBlock TextWrapping="Wrap">
                        More <Run FontFamiliy="Courier">Stuff</Run> here.
                    </TextBlock>
                </StackPanel>
            </ScrollViewer>
        </Expander>


        <GroupBox Header="My List" DockPanel.Dock="Top">
            <ListBox>
                ...
            </ListBox>
        </GroupBox>
    <Grid>