Причиной такого поведения является то, что дочернему элементу Viewbox
предоставляется бесконечное пространство для измерения его желаемого размера.Растягивание TextBox
es до бесконечного Width
не имеет большого смысла, так как это все равно не может быть визуализировано, поэтому возвращается их размер по умолчанию.
Вы можете использовать конвертер для достижения желаемого эффекта.
public class ToWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double gridWidth = (double)value;
return gridWidth * 2/6;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Вы можете подключить все, добавив эти ресурсы.
<Viewbox.Resources>
<local:ToWidthConverter x:Key="ToWidthConverter"/>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Width"
Value="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType={x:Type Grid}},
Converter={StaticResource ToWidthConverter}}"/>
</Style>
</Viewbox.Resources>
ОБНОВЛЕНИЕ
Явозникают проблемы с пониманием исходной проблемы бесконечной ширины сетки.
Метод бесконечного пространства часто используется для определения DesiredSize для UIElement
.Короче говоря, вы даете элементу управления все пространство, которое ему может понадобиться (без ограничений), а затем измеряете его, чтобы получить желаемый размер.Viewbox
использует этот подход для измерения дочернего элемента, но наш Grid
является динамическим по размеру (в коде не задано Height
или Width
), поэтому Viewbox
опускается еще на один уровень в сетках, чтобы видеть детейесли он может определить размер, взяв сумму компонентов.
Однако вы можете столкнуться с проблемами, когда эта сумма компонентов превышает общий доступный размер, как показано ниже.
Я заменил текстовые поля на метки Foo
и Bar
и установил их цвет фона на серый.Теперь мы можем видеть, что Bar
вторгается на территорию Body
, это явно не то, что мы намеревались случиться.
Опять же, корень проблемы в том, что Viewbox
не знает, как разделить бесконечность на 6 равных долей (для сопоставления с шириной столбцов 1*
, 2*
, 1*
, 2*
), так что все, что нам нужно сделать, это восстановить ссылку с шириной сетки.В ToWidthConverter
целью было сопоставить TextBox
'Width
с Grid
s ColumnWidth
из 2*
, поэтому я использовал gridWidth * 2/6
.Теперь Viewbox
может снова решить уравнение: каждый TextBox
получает одну треть gridwidth
, а каждый Label
половину этого (1*
против 2*
).
OfКонечно, когда вы разбираете вещи, вводя новые столбцы, вам нужно следить за тем, чтобы сумма компонентов синхронизировалась с общей доступной шириной.Другими словами, уравнение должно быть разрешимым. Поместите в математику, сумма желаемых размеров (элементов управления, которые вы не ограничивали, меток в нашем примере) и преобразованных размеров (как части gridWidth
, текстовых полей в нашем примере) должна быть меньше чемили равный доступному размеру (gridWidth
в нашем примере).
Я обнаружил, что масштабирование ведет себя хорошо, если вы используете преобразованные размеры для TextBox
es, и пусть размер звезды ColumnWidth
справиться с большинством других.Помня, чтобы остаться в пределах общего доступного размера.
Один из способов повысить гибкость - добавить ConverterParameter
к миксу.
public class PercentageToWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double gridWidth = (double)value;
double percentage = ParsePercentage(parameter);
return gridWidth * percentage;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private double ParsePercentage(object parameter)
{
// I chose to let it fail if parameter isn't in right format
string[] s = ((string)parameter).Split('/');
double percentage = Double.Parse(s[0]) / Double.Parse(s[1]);
return percentage;
}
}
Пример, который делит gridWidth
на 10 равных долей и назначает эти доли соответствующим компонентам.
<Viewbox Stretch="Uniform">
<Viewbox.Resources>
<local:PercentageToWidthConverter x:Key="PercentageToWidthConverter"/>
</Viewbox.Resources>
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Label Content="Field A" Grid.Column="0" />
<TextBox Grid.Column="1"
Width="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType={x:Type Grid}},
Converter={StaticResource PercentageToWidthConverter},
ConverterParameter=2/10}" />
<Label Content="Field B" Grid.Column="2" />
<TextBox Grid.Column="3"
Width="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType={x:Type Grid}},
Converter={StaticResource PercentageToWidthConverter},
ConverterParameter=3/10}" />
<Button Content="Ok" Grid.Column="4"
Width="{Binding ActualWidth,
RelativeSource={RelativeSource AncestorType={x:Type Grid}},
Converter={StaticResource PercentageToWidthConverter},
ConverterParameter=1/10}" />
</Grid>
</Viewbox>
Обратите внимание на доли для каждого элемента управления, сгруппированные как 2 -2 - 2 - 3 - 1 (с 1 для ширины кнопки).
Наконец, в зависимости от того, какое многоразовое использование вам нужно, некоторые другие способысправиться с этим:
- Установить фиксированные размеры для вашего корня
Grid
.Недостатки: - Необходима точная настройка при каждом изменении компонентов (для достижения желаемого соотношения горизонтального / вертикального / размера шрифта)
- Это соотношение может нарушаться в разных темах, версиях Windows, ...
- Добавить
Behavior
.Как и в одном из ответов в вашем связанном сообщении FontSize
, но вместо этого реализовано отображение ширины столбца в части gridWidth
. - Создание пользовательской панели, как предложено @ Grx70.