Wpf 适合特定宽度的字符串长度

Wpf 适合特定宽度的字符串长度,wpf,wpf-controls,Wpf,Wpf Controls,我肯定我错过了一些明显的东西,我有一个区域,我打算在其中绘制文本。我知道它的高度和宽度。我想知道宽度适合多少个字符/单词,最好是个字符。第二个问题,如果这条线太长,我想画第二条线,所以我想我也需要得到文本的高度,包括它认为正确的垂直填充是什么 我还想知道相反的情况,即在一个特定的宽度中可以容纳多少个字符 我假设WPF不受像素限制的事实会对答案产生一些影响 最终,我计划将文本包装在嵌入文本的不规则形状的图像周围 任何指向正确方向的指针都会很好 感谢这是不可能的,因为字符长度不同,例如W比i宽得多(

我肯定我错过了一些明显的东西,我有一个区域,我打算在其中绘制文本。我知道它的高度和宽度。我想知道宽度适合多少个字符/单词,最好是个字符。第二个问题,如果这条线太长,我想画第二条线,所以我想我也需要得到文本的高度,包括它认为正确的垂直填充是什么

我还想知道相反的情况,即在一个特定的宽度中可以容纳多少个字符

我假设WPF不受像素限制的事实会对答案产生一些影响

最终,我计划将文本包装在嵌入文本的不规则形状的图像周围

任何指向正确方向的指针都会很好


感谢

这是不可能的,因为字符长度不同,例如W比i宽得多(除非您使用的是Courier New之类的字体)。

对于WPF,您可以使用该类计算给定文本字符串将使用的宽度-这将取决于实际文本

示例:

FormattedText formattedText = new FormattedText("Hello Stackoverflow", 
                                                System.Globalization.CultureInfo.GetCultureInfo("en-us"), 
                                                FlowDirection.LeftToRight, 
                                                new Typeface("Arial"), FontSize =14, Brushes.Black);
double textWidth = formattedText.Width;
string text  = GetSubStringForWidth("Hello Stackoverflow", 55);
...
public string GetSubStringForWidth(string text, double width)
{
    if (width <= 0)
        return "";

    int length = text.Length;
    string testString;

    while(true)//0 length string will always fit
    {
        testString = text.Substring(0, length);
        FormattedText formattedText = new FormattedText(testString, 
                                                        CultureInfo.GetCultureInfo("en-us"), 
                                                        FlowDirection.LeftToRight, 
                                                        new Typeface("Arial"), 
                                                        FontSize = 14, 
                                                        Brushes.Black);
        if(formattedText.Width <= width)
            break;
        else
            length--;
    }
    return testString;
}
获取给定宽度的子字符串(简化):

FormattedText formattedText = new FormattedText("Hello Stackoverflow", 
                                                System.Globalization.CultureInfo.GetCultureInfo("en-us"), 
                                                FlowDirection.LeftToRight, 
                                                new Typeface("Arial"), FontSize =14, Brushes.Black);
double textWidth = formattedText.Width;
string text  = GetSubStringForWidth("Hello Stackoverflow", 55);
...
public string GetSubStringForWidth(string text, double width)
{
    if (width <= 0)
        return "";

    int length = text.Length;
    string testString;

    while(true)//0 length string will always fit
    {
        testString = text.Substring(0, length);
        FormattedText formattedText = new FormattedText(testString, 
                                                        CultureInfo.GetCultureInfo("en-us"), 
                                                        FlowDirection.LeftToRight, 
                                                        new Typeface("Arial"), 
                                                        FontSize = 14, 
                                                        Brushes.Black);
        if(formattedText.Width <= width)
            break;
        else
            length--;
    }
    return testString;
}
string text=GetSubStringForWidth(“Hello Stackoverflow”,55);
...
公共字符串GetSubStringForWidth(字符串文本,双倍宽度)
{

如果(width@BrokenGlass的答案很好,但是根据应用程序的特点,您可能会发现二进制搜索的性能更好。如果您的大多数字符串适合可用的宽度,或者通常只需要修剪一两个字符,那么线性搜索是最好的。但是,如果您有很多长字符串,那么环将被严重截断,下面的二进制搜索将很好地工作

请注意,availableWidth和fontSize均以独立于设备的单位(1/96英寸)指定。此外,请使用与绘制文本方式匹配的文本格式模式

public static string TruncateTextToFitAvailableWidth(
    string text, 
    double availableWidth, 
    string fontName, 
    double fontSize)
{
    if(availableWidth <= 0)
        return string.Empty;

    Typeface typeface = new Typeface(fontName);

    int foundCharIndex = BinarySearch(
        text.Length,
        availableWidth,
        predicate: (idxValue1, value2) =>
        {
            FormattedText ft = new FormattedText(
                text.Substring(0, idxValue1 + 1), 
                CultureInfo.CurrentCulture, 
                FlowDirection.LeftToRight, 
                typeface, 
                fontSize, 
                Brushes.Black,
                numberSubstitution: null,
                textFormattingMode: TextFormattingMode.Ideal);

            return ft.WidthIncludingTrailingWhitespace.CompareTo(value2);
        });

    int numChars = (foundCharIndex < 0) ? ~foundCharIndex : foundCharIndex + 1;

    return text.Substring(0, numChars);
}

/**
<summary>
See <see cref="T:System.Array.BinarySearch"/>. This implementation is exactly the same,
except that it is not bound to any specific type of collection. The behavior of the
supplied predicate should match that of the T.Compare method (for example, 
<see cref="T:System.String.Compare"/>).
</summary>
*/      
public static int BinarySearch<T>(
    int               length,
    T                 value,
    Func<int, T, int> predicate) // idxValue1, value2, compareResult
{
    return BinarySearch(0, length, value, predicate);
}

public static int BinarySearch<T>(
    int               index,
    int               length,
    T                 value,
    Func<int, T, int> predicate)
{
    int lo = index;
    int hi = (index + length) - 1;

    while(lo <= hi)
    {
        int mid = lo + ((hi - lo) / 2);

        int compareResult = predicate(mid, value);

        if(compareResult == 0)
            return mid;
        else if(compareResult < 0)
            lo = mid + 1;
        else
            hi = mid - 1;
    }

    return ~lo;
}
public静态字符串TruncateTextToFitAvailableWidth(
字符串文本,
双可用宽度,
字符串名称,
双字体大小)
{
如果(可用宽度)
{
FormattedText ft=新的FormattedText(
text.Substring(0,idxValue1+1),
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
字体,
字体大小,
刷子,黑色,
数字替换:空,
textformatingmode:textformatingmode.Ideal);
返回ft.width,包括trailingwhitespace.CompareTo(值2);
});
int numChars=(foundCharIndex<0)~foundCharIndex:foundCharIndex+1;
返回text.Substring(0,numChars);
}
/**
看,这个实现是完全一样的,
但它不绑定到任何特定类型的集合
提供的谓词应该与T.Compare方法的谓词匹配(例如,
).
*/      
公共静态int二进制搜索(
整数长度,
T值,
Func谓词)//idxValue1,value2,compareResult
{
返回二进制搜索(0,长度,值,谓词);
}
公共静态int二进制搜索(
整数索引,
整数长度,
T值,
Func谓词)
{
int lo=指数;
inthi=(索引+长度)-1;

虽然(瞧,这不是不可能的。整个排版都取决于能否做到这一点。历史上,我们有过像MeasureText和MeasureString这样的事情,以及项目上的测量事件。想想看,看看你正在阅读的网页,注意文本是如何适应可用空间的。啊,')但排版不像你那样。这就像building a从屋顶开始。你不知道一个宽度可以容纳多少个字符,你知道一个特定的文本有多宽。如果不知道文本,就不可能计算宽度。排版不会以“未知随机文本”开始要测量。对不起,我不是故意给人这样的印象。我知道文本,我知道它必须插入的行的宽度。我知道字体,字体大小等等。所以我有所有我需要的位来计算它,我只是不知道如何:)很好的开始,我们是否知道如何做相反的事情,或者我是否需要应用某种分而治之的策略?例如,测量“我是否太长而无法适应此空间”,然后如果>可用宽度,测量“我是否太长”如果太短,请尝试介于两者之间的方法?@Ian:编写一个返回符合给定宽度的字符数的方法应该很简单,我会从上面的编辑开始(显然是简化的),如果性能是一个问题,请转到更复杂的问题-我没有做任何测量。是的。未知字符串的每个字符的精确程度如何?不可能,只能“假定”(平均)@Tom Tom:为什么要投反对票?如果你检查答案,你会发现它确实取决于实际文本,我从一开始就说得很清楚。伙计们,迭代算法完全是过火了。你所需要做的就是计算给定空间中字符串过小或过大的百分比,然后用factoryour缩放字体大小答案太复杂了,有一个简单得多的解决方案。您所需要做的就是计算字符串在给定空间中过小或过大的百分比,并使用该系数缩放字体大小。无论是OP还是我们的应用程序,更改字体大小都是不可接受的。