Ищите объяснение поведения WPF Grid ColumnSpan - PullRequest
8 голосов
/ 15 апреля 2011

Я задал вопрос на http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5c7f5cdf-4351-4969-990f-29ce9ec84b87/, но все еще не хватает хорошего объяснения странного поведения.

Запуск следующего XAML показывает, что TextBlock в столбце 0 имеет ширину, превышающую 100, даже если для столбца задана ширина 100. Я думаю, что странность может иметь какое-то отношение к тому, что он обернут в ScrollViewer, но я не не знаю почему. Если я установил MaxWidth для столбцов, он работает нормально, но установка Width не делает.

  1. Почему ширина столбца 0 не учитывается?
  2. Почему размеры столбцов ведут себя по-разному при удалении средства просмотра прокрутки?

Я ценю любое объяснение! Это настоящая головоломка для меня.

<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="300">
    <ScrollViewer HorizontalScrollBarVisibility="Auto" >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100" />
                <ColumnDefinition Width="100" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="textBlock" Text="{Binding ElementName=textBlock, Path=ActualWidth}" />
            <TextBlock Text="column 1" Grid.Column="1" />
            <TextBlock Grid.Row="1" Grid.ColumnSpan="3" Text="text here that is wider than the first two columns combined" />
        </Grid>
    </ScrollViewer>
</Window>

Ответы [ 4 ]

6 голосов
/ 15 апреля 2011

Это очень хороший вопрос, который проверяет пределы нашей интуиции. Он раскрывает детали реализации логики компоновки Grid.

Ширина 100 не соблюдается, потому что:

  1. В третьем столбце нет ничего, что заставляло бы сетку придавать ей ширину.
  2. Длинный текст во втором ряду шире, чем умещается в первых двух столбцах.
  3. Когда ширина сетки не ограничена или не установлена ​​ее родителем, логика ее расположения явно растягивает первый столбец вместо последнего столбца.

Поместив MaxWidth в первый столбец, вы ограничиваете логику компоновки сетки, поэтому она переходит ко второму столбцу и растягивает его. Вы заметите, что в этом сценарии он будет шире, чем 100.

Однако, как только ширина сетки устанавливается на определенное значение или ограничивается его родителем (например, когда в окне нет ScrollViewer), ширина сетки имеет определенное значение, а третий столбец получает ширину, заданную даже хотя это пусто. Теперь код авторазмера Grid деактивирован, и он больше не растягивает ваши столбцы, пытаясь втиснуть этот текст. Это можно увидеть, поместив определенную ширину в сетку, даже если она все еще находится в ScrollViewer.

Редактировать: Теперь, когда я прочитал ответ о поддержке MSDN в вашей исходной ветке, я считаю, что это правильно, то есть, вероятно, это результат реализации присоединенного свойства, а не самой сетки , Тем не менее, принцип тот же, и, надеюсь, мое объяснение достаточно ясно, чтобы понять тонкость здесь.

3 голосов
/ 15 апреля 2011

Краткий ответ:
Это из-за комбинации:
1. Наличие ScrollViewer, который позволяет сетке (если она желает) принимать любой желаемый размер.
2. Сетка не имеет явной ширины.
3. Столбец (Столбец 2), ширина которого не указана, который устанавливает его в 1 *, оставляя его окончательный размер в зависимости от размера сетки и других столбцов.
4. TextBlock, который имеет colspan над тремя столбцами.

Если вы:
1. Удалите scrollviewer, сетка может увеличиваться только до клиентской области окна (что составляет около278 в вашем примере), и длинный текстовый блок должен вписываться в эту ширину, иначе его обрезается.
2. Установите явную ширину сетки, которая снова обрезает текстовый блок, чтобы соответствовать.
3. Установите явную ширину столбца 2, которая обеспечивает фиксированную ширину сетки (100 + 100 + width_of_col2), которая снова подрезает текстовый блок для подгонки.
4. Удалите colspan, столбцы, которые не содержат его и имеют определенную фиксированную ширину, примут эту ширину.

Вот что происходит:
Это грубо ине точное объяснение меры и организации пропусков , однако, это должно дать справедливое представление.

Для начала с col0 доволен 100, col1 с 100 и col2 с 0. Исходя из этого размера сетки будет 100 + 100 + 0 = 200.Когда Grid запрашивает, чтобы его дочерние элементы (текстовые блоки) были измерены, он видит, что первые два текстовых блока помещаются в ширину их столбцов.Однако третьему текстовому блоку требуется 288. Поскольку у сетки нет определенной ширины, и она находится внутри средства просмотра прокрутки, она может увеличить свой размер, если это понадобится одному из его дочерних элементов.Сетка теперь должна увеличить свой размер с 200 до 288 (т.е. на 88).Это означает, что каждый столбец, в который входит этот текстовый блок (все три из них), будет расширяться на 88/3 ~ = 29 пикселей.Это делает col0 = 100 + 29 = 129, col1 = 100 + 29 = 129, col2 = 0 + 29.

Попробуйте это:
Включите прямоугольник, поместите его в col2 и установите ширину прямоугольника равным 20.

Вот что происходит:
Для началас col0 и col1 довольны 100 каждый, так как их отдельным текстовым блокам нужно меньше.col2 счастлив с 20, так как прямоугольник в этом нуждается.На основе этой сетки ширина будет 100 + 100 + 20 = 220.Однако из-за расширяющегося столбца текстовый блок Grid должен увеличить свой размер с 220 до 288 (т.е. на 68).Это означает, что каждый столбец, в который входит этот текстовый блок (все три из них), будет расширен на 68/3 ~ = 23 пикселя.Это делает col0 = 100 + 23 = 123, col1 = 100 + 23 = 123, col2 = 20 + 23 = 43.

HTH.

2 голосов
/ 27 апреля 2011

Вот еще один пример, который показывает проблему с использованием Canvas вместо ScrollViewer:

<Canvas>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" x:Name="textBlock1" Text="{Binding ElementName=textBlock1, Path=ActualWidth}"/>
        <TextBlock Grid.Column="1" x:Name="textBlock2" Text="{Binding ElementName=textBlock2, Path=ActualWidth}"/>
        <TextBlock Grid.Row="1" Grid.ColumnSpan="3" Width="300"/>
    </Grid>
</Canvas>

В этом примере показано, что при наличии неограниченного пространства первые два столбца неправильно расширяются на 33%.У меня нет рабочего эталонного источника для отладки этого прямо сейчас, потому что SP1 сломал эталонный источник .NET4, но откровенно указывать это на строку в исходном файле не поможет, поэтому давайте не будем идти по этому пути.

Вместо этого, мы согласимся, что это определенно ошибка, и мы можем доказать, что это ошибка, устанавливая Grid.MaxWidth с постепенно увеличивающимися значениями, а ширина двух столбцов остается равной 100, независимо от того, насколько она велика.Но если вы оставите Grid.MaxWidth неустановленным и поместите Grid внутри Canvas, тогда значение во время измерения будет double.PositiveInfinity, и это значение будет иметь ширину столбца 133. В результате мы можем предположить, что некоторые какОсобый случай ограничения размера положительной бесконечности не обрабатывается правильно во время вычислений размера столбца.

К счастью, тот же самый эксперимент предлагает простой обходной путь: просто предоставьте абсурдно большое значение для Grid.MaxWidth, когда Gridиспользуется внутри другого элемента управления, который предоставляет ему неограниченное пространство, например ScrollViewer или Canvas.Я рекомендую что-то вроде:

<Grid MaxWidth="1000000">

Этот подход позволяет избежать ошибки, предотвращая ограничение размера, имеющее пробматическое значение положительной бесконечности, при этом практически достигая того же эффекта.

Но это:

<Grid MaxWidth="{x:Static sys:Double.PositiveInfinity}">

вызовет ошибку.

0 голосов
/ 28 апреля 2011

Я сообщил об этой проблеме как об ошибке:

https://connect.microsoft.com/VisualStudio/feedback/details/665448/wpf-grids-columns-width-property-not-honored-when-columnspan-row-forces-grid-to-grow

Пожалуйста, проголосуйте по этой ссылке, если вы согласны с тем, что это ошибка.

...