Scroll AND Stretch the content of an Expander
Asked Answered
L

2

8

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>
Ligni answered 23/12, 2010 at 14:59 Comment(0)
R
8

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.

Rosenberry answered 23/12, 2010 at 23:38 Comment(9)
it works partly. There are 2 flaws: I get this error for all 4 expander => System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Ex1'. BindingExpression:Path=IsExpanded; DataItem=null; target element is 'RowDefinition' (HashCode=61280566); target property is 'Height' (type 'GridLength'), I tried this on the RichTextBox inside The Expander.Content => Height OR MinHeight="{Binding ElementName=Ex1,Path=Height}" but the RichTextBox`s Height does not stretch down ? And when I write much text inside the RTB the text is writing out of the richTextBox...Ligni
Inside the Expander: <Controls:RichTextBox Height="{Binding ElementName=Ex1,Path=ActualHeight}" /> Now I have always the space (height) of the Expander.Header to subtract this should happen in a converter too. Now I need 2 Values inside the Converter: The ActualHeight of the Expander.Header and of Expander.Content to subtract it and return it as new Height for the RichTextBox. But how can I pass 2 values to a converter ?Ligni
It sounds like the RichTextBox control you are using is not set up properly to behave well within the layout system and you're just trying to hack around it to force it to do what it should be doing by default.Rosenberry
well I googled for TextBox and RichTextbox stretching etc... and their seem to exist problems I have to workaround !? I can put the RichTextBox in a Grid with 1 Column/Row and Height to "*" and the RichTExtBox to VErticalAlignment=Stretch that should work but it does NOT! You have any idea then what could be wrong?Ligni
I have also set in the Expander ControlTemplate the Row in the Grid to "*" which holds the ContentPresenter and of this object I set VErticalAlignment=Stretch. What else could there be ? Normally that approach is right but it does not fit for the Expander Content.Ligni
I checked the ControlTemplate of the Expander in Blend Expression and it has a different ControlTemplate for .net 4.0 apps then the one ControlTemplate for .net 4.0 on msdn thats odd. With the Template in Blend I can put a RichTextbox in the Content Area of the Expander and it stretches horizontally... ok seems I change some converter stuff and grid stuff before I can make that proper working.Ligni
ok a big arghh.... I found the evil code... I had another expander_style defined somewhere in a UserControl which had bad code and it was used by the expander_accordion. Same look but different behaviour therefore It took me a while to find that out... Now everything works!Ligni
@John Could you still tell me why I get this errors from your code? => System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=Ex1'. BindingExpression:Path=IsExpanded; DataItem=null; target element is 'RowDefinition' (HashCode=12295594); target property is 'Height' (type 'GridLength'), SAME error message for Ex2,Ex3 and Ex4 of course.Ligni
ok seems I should check that out: joshsmithonwpf.wordpress.com/2008/07/22/…Ligni
K
3

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.

Kalikalian answered 23/12, 2010 at 19:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.