3

我正在使用 avalon edit 编写自定义软件,并且正在寻找一种方法来使行之间的空间(高度)更大。目前,每当用户写完一行并想写另一行时,我都被迫添加一个空行。

我已经开始研究TextView似乎计算 defaultLineHeight 的类,但我唯一能影响的是视觉插入符号的高度,而不是内容本身。

目前我正在考虑让每对线不可见,但我希望有一种更简单的方法来实现在线之间添加更多空间的简单操作。

这是TextView我目前正在检查的课程中的方法。欢迎任何提示或提示。

void CalculateDefaultTextMetrics()
{
    if (defaultTextMetricsValid)
    {
        return;
    }

    defaultTextMetricsValid = true;
    if (formatter != null)
    {
        var textRunProperties = CreateGlobalTextRunProperties();
        using (
            var line = formatter.FormatLine(
                new SimpleTextSource("x", textRunProperties),
                0,
                32000,
                new VisualLineTextParagraphProperties { defaultTextRunProperties = textRunProperties },
                null))
        {
            wideSpaceWidth = Math.Max(1, line.WidthIncludingTrailingWhitespace);
            defaultBaseline = Math.Max(1, line.Baseline);
            defaultLineHeight = Math.Max(1, line.Height);
        }
    }
    else
    {
        wideSpaceWidth = FontSize / 2;
        defaultBaseline = FontSize;
        **defaultLineHeight = FontSize + 3; // bigger value only affects caret height :(**
    }

    // Update heightTree.DefaultLineHeight, if a document is loaded.
    if (heightTree != null)
    {
        heightTree.DefaultLineHeight = defaultLineHeight;
    }
}

谢谢

4

4 回答 4

5

是默认字体中一行的DefaultLineHeight高度,用作每行高度的初始假设。(例如用于计算滚动条位置)

每当一条线被实际测量(TextView.BuildVisualLine)时,测量的高度就会存储在高度树中,覆盖默认高度。这是因为自动换行(或更改字体大小的换行符)会导致每行具有不同的高度。

目前并不真正支持行间距。如果您想添加它,您可以尝试更改 的高度计算VisualLine,例如通过更改VisualLine.SetTextLines().

于 2012-08-31T18:44:50.320 回答
3

包括@Peter Moore 所说的。为了强制文本正确呈现,还需要一个步骤。

底部VisualLine.csVisualLineDrawingVisual负责绘制实际文本但无权访问该类的TextView类。

修改构造函数以包含作为参数并将by 的double lineSpacing所有实例相乘。textLine.HeightlineSpacing

在中,作为现在修改的构造函数的辅助参数VisualLine.Render()传递。在此之后,一切都应该正确绘制。textView.LineSpacingVisualLineDrawingVisual

这是修改后的代码的完整视图:

文本视图.cs

public static readonly DependencyProperty LineSpacingProperty =
    DependencyProperty.Register("LineSpacing", typeof(double), typeof(TextView),
                                new FrameworkPropertyMetadata(1.0));

public double LineSpacing {
    get { return (double) GetValue(LineSpacingProperty); }
    set { SetValue(LineSpacingProperty, value); }
}

视觉线.cs

第 269 行

internal void SetTextLines(List<TextLine> textLines) {
    this.textLines = textLines.AsReadOnly();
    Height = 0;
    foreach (TextLine line in textLines)
        Height += line.Height * textView.LineSpacing;
}

335号线

public double GetTextLineVisualYPosition(TextLine textLine, VisualYPosition yPositionMode) {
    if (textLine == null)
        throw new ArgumentNullException("textLine");
    double pos = VisualTop;
    foreach (TextLine tl in TextLines) {
        if (tl == textLine) {
            switch (yPositionMode) {
            case VisualYPosition.LineTop:
                return pos;
            case VisualYPosition.LineMiddle:
                return pos + tl.Height / 2 * textView.LineSpacing;
            case VisualYPosition.LineBottom:
                return pos + tl.Height * textView.LineSpacing;
            case VisualYPosition.TextTop:
                return pos + tl.Baseline - textView.DefaultBaseline;
            case VisualYPosition.TextBottom:
                return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight;
            case VisualYPosition.TextMiddle:
                return pos + tl.Baseline - textView.DefaultBaseline + textView.DefaultLineHeight / 2;
            case VisualYPosition.Baseline:
                return pos + tl.Baseline;
            default:
                throw new ArgumentException("Invalid yPositionMode:" + yPositionMode);
            }
        }
        else {
            pos += tl.Height * textView.LineSpacing;
        }
    }
    throw new ArgumentException("textLine is not a line in this VisualLine");
}

386 号线

public TextLine GetTextLineByVisualYPosition(double visualTop) {
    const double epsilon = 0.0001;
    double pos = this.VisualTop;
    foreach (TextLine tl in TextLines) {
        pos += tl.Height * textView.LineSpacing;
        if (visualTop + epsilon < pos)
            return tl;
    }
    return TextLines[TextLines.Count - 1];
}

701线

internal VisualLineDrawingVisual Render() {
    Debug.Assert(phase == LifetimePhase.Live);
    if (visual == null)
        visual = new VisualLineDrawingVisual(this, textView.LineSpacing);
    return visual;
}

714线

public VisualLineDrawingVisual(VisualLine visualLine, double lineSpacing) {
    this.VisualLine = visualLine;
    var drawingContext = RenderOpen();
    double pos = 0;
    foreach (TextLine textLine in visualLine.TextLines) {
        textLine.Draw(drawingContext, new Point(0, pos), InvertAxes.None);
        pos += textLine.Height * lineSpacing;
    }
    this.Height = pos;
    drawingContext.Close();
}
于 2017-12-20T01:54:01.797 回答
2

我知道这是一篇旧帖子,但我只是遇到了同样的问题。通过以下修改,我设法很容易地添加了行距:

  1. 添加一个新的double依赖属性来TextView调用LineSpacing,默认值为1.0
  2. 在,VisualLine.SetTextLines乘以line.HeighttextView.LineSpacing
  3. VisualLine.GetTextLineVisualYPositionandVisualLine.GetTextLineByVisualYPosition中,每次出现的tl.Height乘以textView.LineSpacing

然后您可以TextView.LineSpacing直接在代码中或通过自定义 XAML 样式等进行设置。

这似乎是所有必要的。

PS - AvalonEdit 太棒了!

于 2016-09-09T17:45:30.580 回答
1

除了@Robert Jordan 所说的之外,我还必须进行一些更改才能获得令人满意的结果。

首先,要使文本标记覆盖覆盖行的整个高度,请在 BackgroundGeometryBuilder.cs 中更改以下行

ProcessTextLines 方法,第 196 行:

第 215 行:

yield return new Rect(pos, y, 1, line.Height * textView.LineSpacing);

第 259 行:

lastRect = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height * textView.LineSpacing);

第 259 行:

Rect extendSelection = new Rect(Math.Min(left, right), y, Math.Abs(right - left), line.Height * textView.LineSpacing);

我遇到的第二个问题是文本呈现在现在扩展行高的顶部,而不是底部。为了解决这个问题,需要在渲染行之前添加额外的空间,而不是之后。因此,进行以下更改:

VisualLine.cs,第 714 行

public VisualLineDrawingVisual(VisualLine visualLine, double lineSpacing) {
    this.VisualLine = visualLine;
    var drawingContext = RenderOpen();
    double pos = 0;
    foreach (TextLine textLine in visualLine.TextLines) {
        pos +=(textLine.Height * lineSpacing)-textLine.Height
        textLine.Draw(drawingContext, new Point(0, pos), InvertAxes.None);
        pos += textLine.Height;
    }
    this.Height = pos;
    drawingContext.Close();
}

此外,我发现将其转换为支持动态逐行行距很简单。只需将 LineSpacing 属性移动到 VisualLine,然后像这样添加一个 VisualLineTransformer:

class LinePaddingTransformer : IVisualLineTransformer
{
    public LinePaddingTransformer()
    {

    }
    public void Transform(ITextRunConstructionContext context, IList<VisualLineElement> elements)
    {
        int index = context.VisualLine.FirstDocumentLine.LineNumber - 1;
       //You need to calculate your padding from the line index somehow.
       //for example create a list of objects with the spacing in them and pass to this transformer.
        double spacing= MyCalculateLinePaddingMethod(index);  
        context.VisualLine.LineSpacing= spacing;
    }
}

如果您只需要在文本换行的情况下将间距添加到第一行,则需要遍历之前与 LineSpacing 属性相乘的每个位置,并检查 TextLine 是否是集合中的第一行。

于 2017-12-20T18:39:47.947 回答