如何使用C#加载.rtf文件中存在的页眉和页脚?

时间:2018-07-03 09:44:44

标签: c# richtextbox rtf

我使用richtextbox.loadfile(filepath,RichTextBoxStreamType.RichText);将.rtf文件加载到文本编辑器中; 但它不会加载.rtf文件中存在的页眉和页脚,而且我无法静态创建页眉和页脚,因为页眉中的数据对于其他每个.rtf文件都在变化,因此,如何加载带有标头和页脚

1 个答案:

答案 0 :(得分:0)

  • 坏消息是这是不可能的。

RichTextBox没有页面的概念;但是页眉和页脚依赖页面

看看rtff specs,我们发现:它们可以打开。.

  • 每页
  • 左页或右页
  • 或仅在第一页上。

但是没有页面,显示这八种类型中的任何一种都是没有意义的。

  • 好消息是,剥离页眉和页脚并将它们分别放在单独的rtb中并不是很困难。

让我们从查看Rtf开始;在这里,我们看到rtb已经去除了它实际可以显示的所有不需要的东西。因此,页眉和页脚的rtf不再存在。

相反,我们直接从文件中加载原始数据:

string rawRtf = File.ReadAllText(rtfPath);

接下来,我们分析小卷发。比预期的要简单得多;我使用TreeView来显示它们,但是任何树节点结构都可以。.:

treeView1.Nodes.Clear();
TreeNode cn = new TreeNode("rtf tree"); // a root node
cn = cn.Nodes.Add("");                  // first node
for (int i = 1; i < rawRtf.Length; i++)
{
    char p = rawRtf.Text[i - 1];
    char c = rawRtf.Text[i];

    // always watch for escaped curlies (but ignoring escaped blackslashes)
    // either closing or opening else real character:
    if (c=='}' && p != '\\') cn = cn.Parent;
    else if (c== '{' && p != '\\') cn = cn.Nodes.Add("");
    else cn.Text += c;
}
 treeView1.Nodes.Add(cn);

让我们看一下结果:

enter image description here

已加载的文档具有带真实文本的页眉和页脚;都有嵌入式的小卷发。还有页眉和页脚,其中只包含换行符;我们将忽略这些。

现在,我们要从树中选取所有结果。我们重新组装了所有页眉/页脚节点,还原了curl。为此,我们使用一个函数来递归地收集它们。

我们在节点文本的开头寻找这些control words

List<string> hdrftrWords = new List<string>(){
                @"\header ", @"\headerl", @"\headerr", @"\headerf",
                @"\footer ", @"\footerl", @"\footerr", @"\footerf"  };

收集它们很简单:

List<Tuple<string, TreeNode>>  hdrftrRtf = new List<Tuple<string, TreeNode>> ();

foreach (var hf in hdrftrWords)
{
    TreeNode node = treeView1.Nodes[0];
    // there may be more, but we'll only use the 1st..
    List<TreeNode> h1 = new List<TreeNode>();
    h1 = FindNodesByString(node, hf, h1);
    if (h1.Count > 0) hdrftrRtf.Add(new Tuple<string, TreeNode>(hf, h1[0]));
}

这里我们使用了一个小的递归函数来查找以字符串开头的节点:

List<TreeNode> FindNodesByString(TreeNode tn , string text, List<TreeNode> hits)
{
    if (tn.Text.StartsWith(text)) hits.Add(tn);
    foreach (TreeNode n in tn.Nodes) FindNodesByString(n, text, hits);
    return hits;
}

这确实是我们需要除去页眉和页脚的全部。

结果列表在Item1中具有rtf控制字,在Item2中具有节点。

RichTextBoxes中显示它们是最棘手的部分..:

foreach (var rtf in hdrftrRtf)
{
    var rtb = new RichTextBox();
    rtb.SelectedText = "";
    int i = rtb.Rtf.Length - 9;
    string r = "";
    r = JoinNodeTexts(rtf.Item2, "{", "}", ref r);
    r = r.Replace(rtf.Item1, "");
    rtb.Rtf = rtb.Rtf.Insert(i, r);
    rtb.Width = flowLayoutPanel1.ClientSize.Width - 10;
    if (rtb.Text.Trim().Length > 0) flowLayoutPanel1.Controls.Add(rtb);
}

这里是连接所有节点文本的功能..:

string JoinNodeTexts(TreeNode tn, string prefix, string postfix, ref string joined)
{
    joined += prefix + tn.Text + postfix;
    foreach (TreeNode n in tn.Nodes) JoinNodeTexts(n, prefix, postfix, ref joined);
    return joined;
}

我们删除了控制字,因为我们根本不想让rtb认为它必须处理页眉或页脚。我也跳过空的页眉/页脚条目。 (\par被修剪掉了。。)

创建rtb控件后,我们通过添加一个空字符串来欺骗它起作用;然后我们在末尾插入原始的页眉和页脚,再减去一个跳过正常结尾的魔术数字,即跳过换行符,闭合的卷曲然后再添加一些。

将结果添加到FlowLayoutPanel中进行测试。只需简单地复制Text并将其粘贴到实际RTB的开头或结尾即可。

enter image description here

由于我用一个基本为空的rtb作弊,所以我们在树的顶部缺少原始的字体和颜色表。如果页眉/页脚也要显示这些,则也必须从树中解析出这些表。