Связать действие Expander с высотой RowDefinition

У меня есть следующая сетка:

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

                <Expander Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
                    <TextBox />
                </Expander>

Текстовое поле заполняет расширитель. Я хотел бы настроить это так, чтобы при расширении нижней строки высота строки была Auto/*/*, а когда нижняя часть свернута, высота строки была Auto/*/Auto. Я пытался (безуспешно) использовать триггеры стиля для этого и хотел бы сделать это в XAML, а не в коде, насколько это возможно. Заранее спасибо...


person Reinderien    schedule 24.08.2012    source источник
comment
У меня была именно эта проблема прошлой ночью, но я не нашел хорошего решения.   -  person CodingGorilla    schedule 24.08.2012


Ответы (2)


Я могу придумать два простых способа сделать это

Во-первых, нужно отрегулировать RowDefinitions сетки на основе значения Expander.IsExpanded. В моем блоге есть несколько GridHelpers, которые позволяет вам привязывать определения строк и столбцов сетки вместо того, чтобы определять их вручную, что значительно упрощает эту задачу. Используя эти помощники, конечный результат будет выглядеть так:

<Grid local:GridHelpers.RowCount="3">
    <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Setter Property="local:GridHelpers.StarRows" Value="1" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=MyExpander, Path=IsExpanded}" Value="True">
                    <Setter Property="local:GridHelpers.StarRows" Value="1,2" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>

    ...

    <Expander x:Name="MyExpander" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
        <TextBox />
    </Expander>

</Grid>

Второй вариант — использовать Converter и Trigger, которые устанавливают Expander.MinHeight в (Grid.ActualHeight - Row0Content.ActualHeight) / 2 при расширении. У меня также есть MathConverter в моем блоге, который может сделать это проще, или вы можете просто создать свой собственный.

<Grid x:Name="MyGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBox Height="50" Grid.Row="0" />
    <TextBox Grid.Row="1" />

    <Expander Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
        <Expander.Style>
            <Style TargetType="{x:Type Expander }">
                <Setter Property="MinHeight" Value="0" />
                <Style.Triggers>
                    <Trigger Property="IsExpanded" Value="True">
                        <Setter Property="MinHeight" Value="{Binding 
                            ElementName=MyGrid, 
                            Path=ActualHeight,
                            Converter={StaticResource MathConverter},
                            ConverterParameter=((@VALUE-50)/2)" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Expander.Style>

        <TextBox />
    </Expander>
</Grid>

Этот конвертер в моем блоге будет работать только в том случае, если вы заранее знаете высоту Row0, поскольку это обычная IValueConverter, однако довольно легко преобразовать в IMultiValueConverter, если вам нужно также передать высоту Row0. На самом деле у меня уже есть код для этого, но я еще не успел обновить свой пост в блоге.

person Rachel    schedule 24.08.2012
comment
Они кажутся хорошими, но... первый требует дополнительной зависимости, а второй побеждает механизм единиц определения строк, выполняя среднее значение вручную. Поправьте меня, если я ошибаюсь - второй нужно будет изменять всякий раз, когда вы добавляете новую строку в сетку. - person Reinderien; 25.08.2012
comment
@Reinderien Вы правы в том, что вторую реализацию нужно будет настраивать каждый раз, когда вы настраиваете Grid, однако вы можете легко сделать то же самое с IMultiValueConverter и передать ему любые параметры, которые вам нужны, поэтому не имеет значения, что остальная часть сетки выглядит как. Первый - это просто AttachedProperty, который изменяет RowDefinitions всякий раз, когда изменяется инициированное значение, что очень похоже на ваш собственный ответ (что также является допустимым способом сделать это). - person Rachel; 26.08.2012

Пока это мой уродливый обходной путь:

<Window.Resources>
    <Style TargetType="Expander">
        <EventSetter Event="Expanded" Handler="ExpanderGrow"/>
        <EventSetter Event="Collapsed" Handler="ExpanderGrow"/>
    </Style>
</Window.Resources>

... и требуется CS:

    public void ExpanderGrow(object sender, RoutedEventArgs e)
    {
        Expander expander = (Expander)sender;
        Grid grid = (Grid)expander.Parent;
        int index = Grid.GetRow(expander);
        RowDefinition rowdef = grid.RowDefinitions[index];

        rowdef.Height = new GridLength(1,
            expander.IsExpanded ? GridUnitType.Star : GridUnitType.Auto);
    }
person Reinderien    schedule 24.08.2012