Ответ 1
Я бы согласился с тем, что Бен отвечает, что намекает на то, что может происходить под обложками:
Как указывает Бен, WPF игнорирует размер звезды в целях вычисления внутренней минимальной ширины объекта Grid
(возможно, разумно & hellip; я думаю, что есть место для честных дебатов, но ясно, что один возможный и законный дизайн).
Что непонятно (и что Бен не отвечает), почему это должно означать, что звездное измерение также игнорируется, когда приходит время для вычисления ширины столбцов внутри этого внутреннего Grid
. Поскольку, когда ширина вводится снаружи, пропорциональная ширина приведет к усечению содержимого, если необходимо, чтобы сохранить эти пропорции, почему то же самое не происходит, когда ширина вычисляется автоматически на основе минимально необходимых размеров содержимого.
т.е. Я все еще ищу ответ на свой вопрос.
Между тем, ИМХО полезные ответы включают в себя проблемы с этим вопросом. В то время как фактические ответы на мой вопрос сами по себе, они явно полезны для всех, кто может столкнуться с проблемой. Поэтому я пишу этот ответ, чтобы объединить все известные работы (лучше или хуже, одна большая "функция" WPF заключается в том, что всегда существует, по крайней мере, несколько разных способов добиться того же результата:)).
Обходной путь №1:
Используйте UniformGrid
вместо Grid
для внутреннего объекта сетки. Этот объект не имеет всех тех же функций, что и Grid
, и, конечно же, не допускает, чтобы любые столбцы имели разную ширину. Таким образом, это не может быть полезно во всех сценариях. Но он легко справляется с простым здесь:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<UniformGrid Rows="1" Columns="2" Grid.Column="1">
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</UniformGrid>
</Grid>
Обходной путь №2:
Привязать свойство MinWidth
объекта меньшего содержимого (например, здесь, первый Button
в сетке) к свойству ActualWidth
более крупного.
Это, конечно, требует знания того, какой объект имеет наибольшую ширину. В сценариях локализации это может быть проблематично, так как XAML должен быть локализован в дополнение к текстовым ресурсам. Но иногда это необходимо, поэтому & hellip;:)
Это будет выглядеть примерно так (и, по сути, это то, что dub stylee предоставлено ответ здесь):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"
MinWidth="{Binding ElementName=button2, Path=ActualWidth}"/>
<Button x:Name="button2" Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
Вариант (который для краткости я здесь не буду включать) должен был бы использовать MultiBinding
, который принимает все соответствующие элементы управления как входные данные и возвращает наибольший MinWidth
коллекции. Конечно, тогда это связывание будет использоваться для Width
каждого ColumnDefinition
, так что все столбцы были явно заданы наибольшим MinWidth
.
Существуют и другие варианты сценария привязки, в зависимости от того, какую ширину вы хотите использовать и/или установить. Ни один из них не идеален не только из-за потенциальных проблем локализации, но и потому, что он вставляет более явные отношения в XAML. Но во многих сценариях он будет работать отлично.
Обходной путь № 3:
Используя свойство SharedSizeGroup
значений ColumnDefinition
, можно явно заставить группу столбцов иметь одинаковую ширину. В этом подходе затем вычисляется внутренняя минимальная ширина объекта Grid
, и, конечно, ширина тоже заканчивается.
Например:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1" IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
<ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>
Этот подход позволяет использовать Grid
и таким образом получить все обычные функции этого объекта, обращаясь к конкретному поведению, вызывающему озабоченность. Я ожидаю, что это не будет мешать никакому другому законному использованию SharedSizeGroup
.
Однако это подразумевает "Auto"
калибровку и исключает размер "*"
(звездочка). В этом конкретном сценарии это не проблема, но, как и в случае UniformGrid
, он ограничивает один параметр при попытке комбинировать это с другим размером. Например. имея третий столбец, используйте "Auto"
и хотите, чтобы столбцы SharedSizeGroup
заняли оставшееся пространство Grid
.
Тем не менее, это будет работать во многих сценариях без каких-либо проблем.
Обходной путь №4:
Я закончил пересмотр этого вопроса, потому что я столкнулся с вариацией темы. В этом случае я имею дело с ситуацией, когда я хочу иметь разные пропорции для размеров столбцов. Все описанные выше обходные решения предполагают столбцы равного размера. Но я хочу (например), чтобы один столбец имел 25% пространства, а другой столбец имел 75% пробела. Как и раньше, я хочу, чтобы общий размер Grid
соответствовал минимальной ширине, необходимой для всех столбцов.
Это обходное решение подразумевает просто явное вычисление, которое я считаю, что WPF должен делать. То есть беря минимальную ширину содержимого каждого столбца вместе с указанными пропорциями пропорционального размера, вычислите фактическую ширину элемента управления Grid
.
Вот такой способ:
private static double ComputeGridSizeForStarWidths(Grid grid)
{
double maxTargetWidth = double.MinValue, otherWidth = 0;
double starTotal = grid.ColumnDefinitions
.Where(d => d.Width.IsStar).Sum(d => d.Width.Value);
foreach (ColumnDefinition definition in grid.ColumnDefinitions)
{
if (!definition.Width.IsStar)
{
otherWidth += definition.ActualWidth;
continue;
}
double targetWidth = definition.ActualWidth / (definition.Width.Value / starTotal);
if (maxTargetWidth < targetWidth)
{
maxTargetWidth = targetWidth;
}
}
return otherWidth + maxTargetWidth;
}
Этот код находит наименьшую ширину, которая может по-прежнему вмещать каждый столбец размера звезды в этой минимальной ширине и пропорциональном размере столбцов вместе с остальными столбцами, которые не используют размер звезды.
Вы можете вызвать этот метод в соответствующее время (например, в обработчике событий Grid.Loaded
), а затем присвойте его возвращаемому значению свойству Grid.Width
, чтобы заставить ширину правого размера соответствовать минимальной требуемой ширине для все столбцы, сохраняя указанные пропорции.
Аналогичный метод будет делать то же самое для высоты строк.
Обходной путь № 5:
Я предполагаю, что это указывает: можно просто указать размер Grid
явно. Это работает только для контента, размер которого известен заранее, но опять же, во многих сценариях это было бы хорошо. (В других сценариях он обрезает контент, потому что даже если указанный размер слишком мал, когда он явный, WPF идет вперед и применяет пропорции размера звезды).
Я призываю других добавить дополнительные ответы на этот ответ, если они знают о хороших обходах, которые существенно отличаются от тех, которые уже показаны. Кроме того, не стесняйтесь публиковать еще один ответ с помощью вашей работы, и я (при первой возможности:):) добавьте его здесь сам.