7
votes

This is what I want:

1.) When I click my Expander button and it expands it should stretch down to the end of the Grid

see sample image => alt text

2.) When I write more Text than space is available in the RichTextBox within the Expander ScrollBars must be visible and I should be able to scroll down.

Putting a scrollviewer around the Expander content ain't hard but it does not help even with setting on "Auto" they never appear. Set the scrollviewer on "Visible" I can't scroll because the content of the Expander goes down endlessly.

Thats my Sample code:

<Grid Margin="30,0,0,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>
        <StackPanel Background="LightCoral" Orientation="Horizontal">

            <TextBlock Grid.Column="0" Text="Incident type:" VerticalAlignment="Center" />
            <ComboBox  Grid.Column="1"  IsEditable="True" Margin="0,7" Text="{Binding SelectedIncidentReport.IncidentType,Mode=TwoWay}" />

            <TextBlock Grid.Column="0" Grid.Row="1" Text="Teachers name:" VerticalAlignment="Center" />
            <TextBox Grid.Column="1" Grid.Row="1" Height="25" Text="{Binding SelectedIncidentReport.TeacherName,Mode=TwoWay}" />

            <TextBlock Grid.Column="0" Grid.Row="2" Text="Tutor group:" VerticalAlignment="Center" />
            <TextBox Grid.Column="1" Grid.Row="2" Margin="0,7" Text="{Binding SelectedIncidentReport.TutorGroup,Mode=TwoWay}" />
        </StackPanel>

        <Grid Background="LightBlue" Grid.Row="1" >
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>            
                <Expander Background="Purple" Grid.Row="0" Height="Auto" Header="Report details" IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=1}">
                   <Controls:RichTextBox                       
                            VerticalScrollBarVisibility="Auto"                                         
                            Text="{Binding SelectedIncidentReport.ReportDetails,UpdateSourceTrigger=LostFocus,IsAsync=True}"
                            AcceptsReturn="True" 
                            AutoWordSelection="True"
                            AllowDrop="False"
                            SelectionBrush="#FFAC5BCB"
                            HorizontalScrollBarVisibility="Auto" />               
            </Expander>  

        <Expander Background="Red" Grid.Row="1" Header="Action taken" IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=2}">
                <Controls:RichTextBox                                  
                            VerticalScrollBarVisibility="Auto"                                         
                            Text="{Binding SelectedIncidentReport.ActionTaken,UpdateSourceTrigger=LostFocus,IsAsync=True}"
                            AcceptsReturn="True" 
                            AutoWordSelection="True"
                            AllowDrop="False"
                            SelectionBrush="#FFAC5BCB"
                            HorizontalScrollBarVisibility="Auto" />
            </Expander>
            <Expander Background="Lavender" Grid.Row="2" Header="Further action" IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=3}" >
                <Controls:RichTextBox           
                            VerticalScrollBarVisibility="Auto"                                                         
                            Text="{Binding SelectedIncidentReport.FurtherAction,UpdateSourceTrigger=LostFocus,IsAsync=True}"
                            AcceptsReturn="True" 
                            AutoWordSelection="True"
                            AllowDrop="False"
                            SelectionBrush="#FFAC5BCB"
                            HorizontalScrollBarVisibility="Auto" />
            </Expander>
            <Expander Background="YellowGreen" Grid.Row="3" Header="Home contact" IsExpanded="{Binding SelectedExpander, Mode=TwoWay, Converter={StaticResource ExpanderToBooleanConverter}, ConverterParameter=4}" >

                <Controls:RichTextBox                        
                            VerticalScrollBarVisibility="Auto"                                                         
                            Text="{Binding SelectedIncidentReport.HomeContact,UpdateSourceTrigger=LostFocus,IsAsync=True}"
                            AcceptsReturn="True" 
                            AutoWordSelection="True"
                            AllowDrop="False"
                            SelectionBrush="#FFAC5BCB"
                            HorizontalScrollBarVisibility="Auto" />

            </Expander>
        </Grid>
        <Grid Background="LawnGreen" Grid.Row="2" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Documents:" Grid.Column="0" />
            <View:DocumentComboView  DataContext="{Binding Path=SelectedIncidentReport.Documents}" Grid.Column="1" HorizontalAlignment="Stretch"  />
        </Grid>

    </Grid>
2

2 Answers

8
votes

I think what you're looking for is a mix of Auto and * sized Rows: Auto when collapsed, * when expanded. There are a lot of ways you can achieve this switching. A simple one is to bind the row heights to the expanders through a converter. The XAML would look like this:

<Grid Background="LightBlue" Grid.Row="1" >
    <Grid.RowDefinitions>
        <RowDefinition Height="{Binding ElementName=Ex1, Path=IsExpanded, Converter={StaticResource ExpandedToGridLengthConverter}}" />
        <RowDefinition Height="{Binding ElementName=Ex2, Path=IsExpanded, Converter={StaticResource ExpandedToGridLengthConverter}}" />
        <RowDefinition Height="{Binding ElementName=Ex3, Path=IsExpanded, Converter={StaticResource ExpandedToGridLengthConverter}}" />
        <RowDefinition Height="{Binding ElementName=Ex4, Path=IsExpanded, Converter={StaticResource ExpandedToGridLengthConverter}}" />
    </Grid.RowDefinitions>
    <Expander Grid.Row="0" x:Name="Ex1" ...>
        <RichTextBox ... />
    </Expander>

    <Expander Grid.Row="1" x:Name="Ex2" ...>
        ...
    </Expander>
    ...
</Grid>

And here's a simple version of the converter:

public class ExpandedToGridLengthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is bool))
            return GridLength.Auto;

        if ((bool)value)
            return new GridLength(1, GridUnitType.Star);

        return GridLength.Auto;
    }

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

Now the available space will be split between the open expanders and the collapsed ones will only take up as much as their header needs. If the text gets too long for one of the expanded ones the ScrollViewer should take over and start scrolling the text inside that * area.

2
votes

I recently had to do something like this. I used very similar code to what you have but was able to achieve the desired result using the code behind the page. Try something like this:

WPF

<Grid Grid.Row="1"
        Name="pageGrid" Margin="0,10,0,0">
        <Grid.RowDefinitions>
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
            <RowDefinition
                MinHeight="25"
                Height="*" />
        </Grid.RowDefinitions>
        <Expander
            Grid.Row="0"
            Header="header1"
            Name="expander1"
            Margin="0,0,0,0"
            VerticalAlignment="Top"
            FontSize="18"
            IsExpanded="True">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">                    
                test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="1"
            Header="header2"
            Margin="0,0,0,0"
            Name="expander2"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                        test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="2"
            Header="header3"
            Margin="0,0,0,0"
            Name="expander3"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                        test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="3"
            Header="header4"
            Margin="0,0,0,0"
            Name="expander4"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                    test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="4"
            Header="header5"
            Margin="0,0,0,0"
            Name="expander5"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                    test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="5"
            Header="header6"
            Margin="0,0,0,0"
            Name="expander6"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock
                    Background="#336699FF"
                    Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                    test
                </TextBlock>
            </Grid>
        </Expander>
        <Expander
            Grid.Row="6"
            Header="header7"
            Margin="0,0,0,0"
            Name="expander7"
            VerticalAlignment="Top"
            FontSize="18">
            <Grid>
                <TextBlock Background="#336699FF" Padding="5"
                    TextWrapping="Wrap"
                    Margin="30,5,10,5">
                    text
                </TextBlock>
            </Grid>
        </Expander>
    </Grid>

In the window code behind I used C# and have this code:

C#

/// <summary>
/// Interaction logic for _07Slide.xaml
/// </summary>
public partial class _07Slide : Page
{
    GridLength[] starHeight;

    public _07Slide()
    {
        InitializeComponent();

        starHeight = new GridLength[pageGrid.RowDefinitions.Count];
        starHeight[0] = pageGrid.RowDefinitions[0].Height;
        starHeight[1] = pageGrid.RowDefinitions[2].Height;
        starHeight[2] = pageGrid.RowDefinitions[2].Height;
        starHeight[3] = pageGrid.RowDefinitions[2].Height;
        starHeight[4] = pageGrid.RowDefinitions[2].Height;
        starHeight[5] = pageGrid.RowDefinitions[2].Height;
        starHeight[6] = pageGrid.RowDefinitions[2].Height;
        ExpandedOrCollapsed(expander1);
        ExpandedOrCollapsed(expander2);
        ExpandedOrCollapsed(expander3);
        ExpandedOrCollapsed(expander4);
        ExpandedOrCollapsed(expander5);
        ExpandedOrCollapsed(expander6);
        ExpandedOrCollapsed(expander7);


        expander1.Expanded += ExpandedOrCollapsed;
        expander1.Collapsed += ExpandedOrCollapsed;
        expander2.Expanded += ExpandedOrCollapsed;
        expander2.Collapsed += ExpandedOrCollapsed;
        expander3.Expanded += ExpandedOrCollapsed;
        expander3.Collapsed += ExpandedOrCollapsed;
        expander4.Expanded += ExpandedOrCollapsed;
        expander4.Collapsed += ExpandedOrCollapsed;
        expander5.Expanded += ExpandedOrCollapsed;
        expander5.Collapsed += ExpandedOrCollapsed;
        expander6.Expanded += ExpandedOrCollapsed;
        expander6.Collapsed += ExpandedOrCollapsed;
        expander7.Expanded += ExpandedOrCollapsed;
        expander7.Collapsed += ExpandedOrCollapsed;

    }

    void ExpandedOrCollapsed(object sender, RoutedEventArgs e)
    {
        ExpandedOrCollapsed(sender as Expander);
    }

    void ExpandedOrCollapsed(Expander expander)
    {
        var rowIndex = Grid.GetRow(expander);
        var row = pageGrid.RowDefinitions[rowIndex];
        if (expander.IsExpanded)
        {
            row.Height = starHeight[rowIndex];
            row.MinHeight = 25;                
        }
        else
        {
            starHeight[rowIndex] = row.Height;
            row.Height = GridLength.Auto;
            row.MinHeight = 0;
        }
    }
}

In this example the expanders will all grow to fill the grid completely. If you wanted to you could modify this to collapse the other expanders when one is selected.