0

我使用 WPF。我的应用程序有一些文本块,里面有可更改的文本。每个都有 200 的宽度和 150 的高度。问题是我有 7 个这样的文本块,我希望它们具有相同的字体大小。文本必须自动调整。我知道这可以自动调整它们。但是当一个句子里面有一个句子而另一个只有两个词时,字体大小就会如此不同......我需要异步重新计算大小(例如创建一些像 OnTextChange 这样的事件)。块内的文本动态变化。如何写一个函数?我想传递 3 个参数:文本、字体(字体系列 + 字体样式)和文本块大小,并返回适合的字体大小。

4

2 回答 2

2

确定合适字体大小的最佳方法是测量任意大小的文本,然后乘以它的大小与区域大小的比率。

例如,如果你测量文本并且它是它所在容器大小的一半,你可以将它乘以 2,它应该会填满容器。您想选择要使用的宽度或高度比的最小值。

在 WPF 中,FormattedText 类进行文本测量。

public double GetFontSize(string text, Size availableSize, Typeface typeFace)
{
    FormattedText formtxt = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, 10, Brushes.Black);

    double ratio = Math.Min(availableSize.Width / formtxt.Width, availableSize.Height / formtxt.Height);

    return 10 * ratio;
}

每当您更改 TextBlocks 的文本时,您都将使用此函数,如下所示:

txtBlock.FontSize = GetFontSize(txt.Text, new Size(txt.ActualWidth, txt.ActualHeight), new Typeface(txt.FontFamily, txt.FontStyle, txt.FontWeight, txt.FontStretch));

编辑:

出于实用性的目的,您可能希望能够使文本在此预定义的边界矩形中垂直居中。一个很好的方法是将 TextBlock 包装在另一个对象中,例如 Border 元素。通过这种方式,您可以告诉 TextBlock 在边框的中心对齐,并且可以自动调整大小以适合其内容。

于 2012-06-01T17:25:20.297 回答
0

行。工作正常。但我还有另一个问题。我在 MainWindow.cs 中写了 2 个方法:

    private void fitFontSize()
    {
        propertiesList.Clear();

        TextUtils.FontProperty fontProps = new TextUtils.FontProperty();
        foreach (TextBlock tb in findVisualChildren<TextBlock>(statusOptionsGrid))
        {
            fontProps.Text = tb.Text;
            fontProps.Size = new Size(tb.ActualWidth, tb.ActualHeight);
            fontProps.FontFamily = tb.FontFamily;
            fontProps.FontStyle = tb.FontStyle;
            fontProps.FontWeight = tb.FontWeight;
            fontProps.FontStretch = tb.FontStretch;
            propertiesList.Add(fontProps);
        }

        MessageBox.Show(TextUtils.recalculateFontSize(propertiesList) + "");
    }

    public IEnumerable<T> findVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in findVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

之后,我创建了一个用于文本处理的新类。这是代码:

public class TextUtils
{
    public class FontProperty
    {
        public FontFamily FontFamily { get; set; }
        public FontStyle FontStyle { get; set; }
        public FontWeight FontWeight { get; set; }
        public FontStretch FontStretch { get; set; }
        public string Text { get; set; }
        public Size Size { get; set; }

        public Typeface getTypeFace()
        {
            return new Typeface(FontFamily, FontStyle, FontWeight, FontStretch);
        }
    }

    public static double recalculateFontSize(List<FontProperty> propertiesList)
    {
        List<double> fontSizes = new List<double>();
        foreach (FontProperty fp in propertiesList)
        {
            fontSizes.Add(getFontSizeForControl(fp));
        }

        return fontSizes.Min<double>();
    }

    private static double getFontSizeForControl(FontProperty fp)
    {
        string text = fp.Text;
        Size availableSize = fp.Size;
        Typeface typeFace = fp.getTypeFace();

        FormattedText formtxt = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeFace, 10, Brushes.Black);
        double ratio = Math.Min(availableSize.Width / formtxt.Width, availableSize.Height / formtxt.Height);

        return 10 * ratio;
    }
}

代码看起来很糟糕,但我稍后会更正它......

行。现在我想创建一个新的计时器,它每秒检查一次字体大小。当我尝试在其中使用 fitFontSize() 方法时,我得到消息:“调用线程无法访问此对象,因为不同的线程拥有它。” 如何做到这一点以避免这样的问题?我尝试(只是尝试)创建调用此方法的新线程。但是 findVisualChildren<>() 方法也有同样的问题——它在 fitFontSize() 中调用。我没有任何想法如何解决我的问题...

于 2012-06-02T17:32:57.497 回答