Заставить сетку WPF / SL игнорировать дочерний элемент при определении размера - PullRequest
4 голосов
/ 31 января 2011

У меня есть Grid с несколькими дочерними элементами, одним из которых является ScrollViewer. Я хочу, чтобы размер сетки определялся на основе всех его дочерних элементов , за исключением ScrollViewer, который я хочу просто занять пространство, которое создается путем определения размера сетки для остальных дочерних элементов. (Например, Grid имеет размер 2x2, а ScrollViewer находится в строке 0, столбце 0, и поэтому для определения размеров сетки достаточно трех других элементов таблицы.)

Есть хороший способ сделать это? Я рассмотрел создание пользовательской панели для замены Grid или для включения ScrollViewer, но ни при каких обстоятельствах во время вызовов MeasureOverride / ArrangeOverride я не получаю вызов, который может сказать мне об окончательной ширине / высоте строки сетки / столбец, который мне небезразличен (например, строка 0, столбец 0).

Одна мысль, которая у меня возникла, состояла в том, чтобы извлечь из Grid и вызвать базовый MeasureOverride / ArrangeOverride, но удалить ScrollViewer из дочерних элементов Grid прямо перед вызовом (и вернуть его после), но возиться с визуальным деревом во время вычисления макета кажется плохой идеей.

Вот пример:

<Grid x:Name="LayoutRoot" Background="White">
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ScrollViewer Grid.Row="0" Grid.Column="0" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto">
            <Button Height="300" Width="300"/>
        </ScrollViewer>
        <Button Grid.Row="1" Grid.Column="0" Height="100" Width="100" Content="1,0"/>
        <Button Grid.Row="0" Grid.Column="1" Height="100" Width="100" Content="0,1"/>
        <Button Grid.Row="1" Grid.Column="1" Height="100" Width="100" Content="1,1"/>
    </Grid>
</Grid>

Я бы хотел, чтобы размер сетки не менялся при изменении размера кнопки в ScrollViewer - например, я хочу, чтобы сетка предоставляла ScrollViewer квадрат 100x100, который определяется остальным содержимым сетки. И если бы я изменил каждую из 3 кнопок 100x100 на 200x200, я бы хотел, чтобы ScrollViewer получал 200x200 и т. Д.

Пример Павла пока что приближает меня к нему: строки / столбцы таблицы имеют соответствующий размер, но ScrollViewer не адаптируется к заданному размеру при вызове Arrange. Смотрите ниже:

Image showing effect of Pavlo's NoSizeDecorator

Ответы [ 2 ]

7 голосов
/ 31 января 2011

Если я правильно понял, что вы хотите, то вы можете сделать следующий трюк.Создайте декоратор, который будет запрашивать 0 пробелов на этапе измерения и распределит дочернему элементу все заданное пространство на этапе аранжировки:

public class NoSizeDecorator : Decorator
{
    protected override Size MeasureOverride(Size constraint) {
        // Ask for no space
        Child.Measure(new Size(0,0));
        return new Size(0, 0);
    }        
}

И ваш XAML будет выглядеть так:*

1 голос
/ 04 мая 2018

Ответ Павла Глазкова очень хорошо работает для меня! Я использовал его для элемента управления, который не хочет указывать явные размеры ... Я добавил логику и свойства, чтобы победить одно измерение:

public sealed class NoSizeDecorator
            : Decorator
    {
        /// <summary>
        /// Sets whether the width will be overridden.
        /// </summary>
        public static readonly DependencyProperty DisableWidthOverrideProperty
                = DependencyProperty.Register(
                        nameof(NoSizeDecorator.DisableWidthOverride),
                        typeof(bool),
                        typeof(NoSizeDecorator),
                        new FrameworkPropertyMetadata(
                                false,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));

        /// <summary>
        /// Sets whether the width will be overridden.
        /// </summary>
        public bool DisableWidthOverride
        {
            get => (bool)GetValue(NoSizeDecorator.DisableWidthOverrideProperty);
            set => SetValue(NoSizeDecorator.DisableWidthOverrideProperty, value);
        }

        /// <summary>
        /// Sets whether the height will be overridden.
        /// </summary>
        public static readonly DependencyProperty DisableHeightOverrideProperty
                = DependencyProperty.Register(
                        nameof(NoSizeDecorator.DisableHeightOverride),
                        typeof(bool),
                        typeof(NoSizeDecorator),
                        new FrameworkPropertyMetadata(
                                false,
                                FrameworkPropertyMetadataOptions.AffectsMeasure));

        /// <summary>
        /// Sets whether the height will be overridden.
        /// </summary>
        public bool DisableHeightOverride
        {
            get => (bool)GetValue(NoSizeDecorator.DisableHeightOverrideProperty);
            set => SetValue(NoSizeDecorator.DisableHeightOverrideProperty, value);
        }


        protected override Size MeasureOverride(Size constraint)
        {
            UIElement child = Child;
            if (child == null)
                return new Size();
            constraint
                    = new Size(
                            DisableWidthOverride
                                    ? constraint.Width
                                    : 0D,
                            DisableHeightOverride
                                    ? constraint.Height
                                    : 0D);
            child.Measure(constraint);
            return new Size(
                    DisableWidthOverride
                            ? child.DesiredSize.Width
                            : 0D,
                    DisableHeightOverride
                            ? child.DesiredSize.Height
                            : 0D);
        }
    }
...