仅自动调整 wpf 控件字体的大小

问题描述 投票:0回答:1

我有一个看起来像这样的网格布局:

this.

这是它的代码:

<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>

需要这种行为:

This

唯一缺少的是在屏幕上调整每个控件中文本的大小,以调整大小以利用该控件中的可用空间。

我尝试使用

Viewbox
,但无论
Stretch
属性的值如何,它都会更改控件的大小,我不知道如何强制它根据网格保持大小。

我主要是在这篇文章中寻找答案: 如何自动缩放一组控件的字体大小?

wpf xaml uwp controls
1个回答
0
投票

就我所能想象的而言,不会有一个千篇一律的解决方案,但这是针对您的特定问题的解决方案,它还展示了两种不同的处理方式。

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
,并重新模板化它们。这确实要复杂得多。不过,这应该可以满足您的文字示例。

© www.soinside.com 2019 - 2024. All rights reserved.