我有一个看起来像这样的网格布局:
.
这是它的代码:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2.5*"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="2.5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="2.5*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="username" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Text="Username"
GotFocus="RemoveLabel" LostFocus="RestoreLabel"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<TextBox x:Name="password" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Text="Password"
GotFocus="RemoveLabel" LostFocus="RestoreLabel"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<Button x:Name="signUp" Grid.Row="5" Grid.Column="1" Content="Sign up"/>
<Button x:Name="signIn" Grid.Row="5" Grid.Column="3" Content="Sign in"/>
</Grid>
需要这种行为:
唯一缺少的是在屏幕上调整每个控件中文本的大小,以调整大小以利用该控件中的可用空间。
我尝试使用
Viewbox
,但无论 Stretch
属性的值如何,它都会更改控件的大小,我不知道如何强制它根据网格保持大小。
我主要是在这篇文章中寻找答案: 如何自动缩放一组控件的字体大小?
就我所能想象的而言,不会有一个千篇一律的解决方案,但这是针对您的特定问题的解决方案,它还展示了两种不同的处理方式。
public static class AutoScale
{
public static readonly DependencyProperty AutoscaleFontProperty = DependencyProperty.RegisterAttached(
"AutoscaleFont",
typeof(bool),
typeof(AutoScale),
new PropertyMetadata((sender, e) =>
{
if (!(sender is Control c))
throw new NotSupportedException($"AutoscaleFont is for Control-derived classes only");
if (e.NewValue == e.OldValue || !(e.NewValue is bool value))
return;
if (value)
c.SizeChanged += OnSizeChangedRescaleFont;
else
c.SizeChanged -= OnSizeChangedRescaleFont;
}));
private static void OnSizeChangedRescaleFont(object sender, SizeChangedEventArgs e)
{
if (!(sender is Control c))
throw new NotSupportedException($"AutoscaleFont is for Control-derived classes only");
if (c is TextBox)
{
c.FontSize = c.ActualHeight * 0.8;
return;
}
Border border = null;
EnumVisual(c, fe =>
{
if (c is Button && fe is Border b)
{
border = b;
return true;
}
return false;
});
if (border == null)
return;
if (!(border.Child is FrameworkElement child))
return;
double scale = 1;
if (child.ActualWidth / child.ActualHeight > border.ActualWidth / border.ActualHeight)
{
// fit to width
scale = border.ActualWidth / child.ActualWidth;
}
else
{
// fit to height
scale = border.ActualHeight / child.ActualHeight;
}
child.RenderTransformOrigin = new Point(0.5, 0.5);
child.RenderTransform = new ScaleTransform
{
ScaleX = scale,
ScaleY = scale
};
}
public static bool GetAutoscaleFont (DependencyObject obj)
{
return (bool)obj.GetValue(AutoscaleFontProperty);
}
public static void SetAutoscaleFont(DependencyObject obj, bool value)
{
obj.SetValue(AutoscaleFontProperty, value);
}
private static void EnumVisual(FrameworkElement myVisual, Func<FrameworkElement, bool> action)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
{
// Retrieve child visual at specified index value.
FrameworkElement child = VisualTreeHelper.GetChild(myVisual, i) as FrameworkElement;
if (child == null)
continue;
// Do processing of the child visual object.
if (action != null)
{
if (action(child))
break;
}
// Enumerate children of the child visual object.
EnumVisual(child, action);
}
}
}
要消费,只需说:
<TextBox x:Name="username"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="3"
Text="Username"
local:AutoScale.AutoscaleFont="True"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" />
等
这个的肉在
OnSizeChangedRescaleFont
。对任何特定控件执行此操作的方法将取决于控件。这是我认为为默认Button
和默认TextBox
缩放字体的最佳方式。
您会注意到这些是完全不同的方法 - 对于
TextBox
,我只是将 FontSize
属性设置为实际高度的倍数,因为 TextBox
可以水平滚动,而您可能不希望无论如何,字体大小都会随着人们的输入而缩小。
对于
Button
内容是静态的,一旦找到 Border
及其子级,您就可以使用 RenderTransform
使其随着窗口大小的调整而缩放。这会根据内容的宽度与按钮的宽度进行最佳匹配。
当然,这远非完美,但希望它能展示概念并包含您可以用来构建的代码。一个完全健壮的解决方案将涉及子类化您的控件,覆盖
ArrangeOverride
,并重新模板化它们。这确实要复杂得多。不过,这应该可以满足您的文字示例。