GridSplitter с минимальными ограничениями - PullRequest
15 голосов
/ 19 октября 2010

Я хочу макет Grid с двумя рядами и разделителем между ними. Строки должны иметь минимальную высоту 80 пикселей.

Этот код прекрасно работает:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" MinHeight="80" />
        <RowDefinition Height="5" />
        <RowDefinition Height="*" MinHeight="80" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
    <GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
    <TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>

Но я хочу, чтобы верхняя строка имела автоматическую высоту, пока пользователь не изменит ее вручную с помощью сплиттера. Поэтому я изменил код на это:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" MinHeight="80" />
        <RowDefinition Height="5" />
        <RowDefinition Height="*" MinHeight="80" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
    <GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
    <TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>

И есть проблема. Splitter все еще удовлетворяет ограничениям строки, но он начинает бесконечно увеличивать высоту верхней строки, если я перетаскиваю сплиттер слишком низко. В результате нижний ряд будет полностью ниже нижней границы окна.

Я сделал несколько Reflector для кода GridSplitter и вижу, что он использует другую логику, если строки имеют Авто или звездную высоту.

Любые предложения, как я могу "исправить" это?

Ответы [ 2 ]

6 голосов
/ 20 октября 2010

Я разработал обходной путь для этой проблемы.Суть в том, чтобы установить MaxHeight для верхнего ряда, пока мы перетаскиваем сплиттер.Вот код:

public class FixedGridSplitter : GridSplitter
{
    private Grid grid;
    private RowDefinition definition1;
    private double savedMaxLength;

    #region static

    static FixedGridSplitter()
    {
        new GridSplitter();
        EventManager.RegisterClassHandler(typeof(FixedGridSplitter), Thumb.DragCompletedEvent, new DragCompletedEventHandler(FixedGridSplitter.OnDragCompleted));
        EventManager.RegisterClassHandler(typeof(FixedGridSplitter), Thumb.DragStartedEvent, new DragStartedEventHandler(FixedGridSplitter.OnDragStarted));
    }

    private static void OnDragStarted(object sender, DragStartedEventArgs e)
    {
        FixedGridSplitter splitter = (FixedGridSplitter)sender;
        splitter.OnDragStarted(e);
    }

    private static void OnDragCompleted(object sender, DragCompletedEventArgs e)
    {
        FixedGridSplitter splitter = (FixedGridSplitter)sender;
        splitter.OnDragCompleted(e);
    }

    #endregion

    private void OnDragStarted(DragStartedEventArgs sender)
    {            
        grid = Parent as Grid;
        if (grid == null)
            return;            
        int splitterIndex = (int)GetValue(Grid.RowProperty);
        definition1 = grid.RowDefinitions[splitterIndex - 1];
        RowDefinition definition2 = grid.RowDefinitions[splitterIndex + 1];
        savedMaxLength = definition1.MaxHeight;            

        double maxHeight = definition1.ActualHeight + definition2.ActualHeight - definition2.MinHeight;            
        definition1.MaxHeight = maxHeight;
    }

    private void OnDragCompleted(DragCompletedEventArgs sender)
    {
        definition1.MaxHeight = savedMaxLength;
        grid = null;
        definition1 = null;
    }
}

Затем просто замените GridSplitter на FixedGridSplitter.

Примечание: этот код не является общим - он не поддерживает столбцы и предполагает, что в нижней строке указано значение MinHeight.

6 голосов
/ 20 октября 2010

Я сам несколько раз сталкивался с этой проблемой.Похоже, что GridSplitter не очень хорошо работает с Auto.Тем не менее, я нашел потенциальный обходной путь.

Вы можете указать значение объекта GridLength, используя «звездные коэффициенты».Это действует как множитель для рассматриваемой длины.

В вашем примере, если вы возьмете строку, которую хотите оставить звездой, и установите для коэффициента звезды действительно большое число, строка займетвсе доступное пространство (заставляя другой ряд становиться его минимальной высотой).Хотя это не то же самое, что «auto» (высота первого ряда не определяется высотой содержимого), это может приблизить вас.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" MinHeight="80" />
        <RowDefinition Height="5" />
        <RowDefinition Height="10000*" MinHeight="80" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
    <GridSplitter Grid.Row="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Red" />
    <TextBlock Grid.Row="2" Text="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
</Grid>
...