我使用richtextbox.loadfile(filepath,RichTextBoxStreamType.RichText);将.rtf文件加载到文本编辑器中; 但它不会加载.rtf文件中存在的页眉和页脚,而且我无法静态创建页眉和页脚,因为页眉中的数据对于其他每个.rtf文件都在变化,因此,如何加载带有标头和页脚
答案 0 :(得分:0)
RichTextBox
没有页面的概念;但是页眉和页脚依赖页面。
看看rtff specs,我们发现:它们可以打开。.
但是没有页面,显示这八种类型中的任何一种都是没有意义的。
让我们从查看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);
让我们看一下结果:
已加载的文档具有带真实文本的页眉和页脚;都有嵌入式的小卷发。还有页眉和页脚,其中只包含换行符;我们将忽略这些。
现在,我们要从树中选取所有结果。我们重新组装了所有页眉/页脚节点,还原了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的开头或结尾即可。
由于我用一个基本为空的rtb作弊,所以我们在树的顶部缺少原始的字体和颜色表。如果页眉/页脚也要显示这些,则也必须从树中解析出这些表。