我正在设计文本渲染器。我正在建立如何将字符串分成几行以适合文本框的逻辑。我要这样做的方法是,首先将完整的字符串分成“单词”,“空格”和“换行符”,然后构建一种算法来测量一行中可以容纳多少行,然后再移动到下一行。
但是,“ Word”必须是一个类/结构,因为它要保留“ FontStyle”,“ Colour”等附加属性。“ Space”和“ NewLine”仅是标记-不需要任何标记数据。
目前,我具有以下框架:
interface ILineComponent
{
}
struct Word : ILineComponent
{
public string Text;
public FontStyle Style;
public Colour Colour;
public Word(string text, FontStyle style, Colour colour)
{
Text = text;
Style = style;
Colour = colour;
}
}
struct Space : ILineComponent
{
}
struct NewLine : ILineComponent
{
}
struct Line
{
public List<ILineComponent> Segments;
public Line(List<ILineComponent> segments)
{
Segments = segments;
}
}
然后,我的想法是通过直线,并测量将一条线(或单词,...,换行符)分解为另一条线之前,要在一行(或单词,...,换行符)中容纳多少(单词,空格,...,单词,空格)线。目前,这将利用如下逻辑:
foreach (ILineComponent component in line)
{
if (component is Word)
//..
else if (component is Space)
//...
else if (component is NewLine)
//...
}
但是此设计违反了CA1040。
我该如何更好地设计?
首先,我认为Space
的定义不完整。没有字体也无法确定空间的宽度。因此,我认为空间应类似于Word
。也许它不需要颜色,当然也不需要文本作为参数。
struct Space : ILineComponent
{
public readonly string Text = " ";
public FontStyle Style;
public Word(FontStyle style)
{
Style = style;
}
}
我也认为此代码具有误导性
foreach (ILineComponent component in line)
由于您尚不知道,所以会有多少行,所以变量line
不正确。该值应为componentsOfText
或类似值。在循环内,您将在需要时开始新行。
接下来,我建议您将这三个组件需要做的所有事情都放入界面中。据我了解,那就是:
interface ILineComponent
{
int Measure();
bool IsTrimmedAtEndOfLine;
bool TerminatesLine;
}
您的代码如下所示:
// IList<LineComponent> is a line
// IList< -"- > are many lines
// Maybe you want to define an alias for that, or even a class
IList<IList<ILineComponent>> lines = new ...;
int remainingSpace = 2000; // px or whatever
while (componentsOfText.Length > 0)
{
component = componentsOfText[0];
var space = component.Measure();
if (space > remainingSpace)
{
// finish current line and start a new one,
// i.e. add a new List<LineComponent>,
// reset remaining space,
// do the line post processing (e.g. space width adjustment)
// Do not remove component from the list
continue;
}
if (component.TerminatesLine)
{
// Finish current line and start a new line
// just as before
}
remainingSpace -= space;
// Remove component from the list
}
对于“完成当前行并开始新的行::
var lastitem = line[line.Count - 1];
if (lastitem.IsTrimmedAtEndOfLine)
{
line.Remove(lastitem);
}
// start the second pass for calculating the width of a space etc.