【发布时间】:2019-12-11 09:13:11
【问题描述】:
我正在尝试使用 openxml sdk v2.5 和 C# 以编程方式在 word 文档中实现多级列表。我使用以下代码在多级列表中显示标题。我正在调用 AddHeading 方法并传递相应的参数,如下所示。我的预期结果如下。
1. Parent
1.1. childItem
1.1.1. subchildItem
1.2. childItem
2. Parent
2.1. childItem
3. Parent
但我得到的输出是
1. Parent
1. childItem
1. subchildItem
2. childItem
2. Parent
1. childItem
3. Parent
public static void AddHeading(WordprocessingDocument document, string colorVal, int fontSizeVal, string styleId, string styleName, string headingText, int numLvlRef, int numIdVal)
{
StyleRunProperties styleRunProperties = new StyleRunProperties();
Color color = new Color() { Val = colorVal };
DocumentFormat.OpenXml.Wordprocessing.FontSize fontSize1 = new DocumentFormat.OpenXml.Wordprocessing.FontSize();
fontSize1.Val = new StringValue(fontSizeVal.ToString());
styleRunProperties.Append(color);
styleRunProperties.Append(fontSize1);
AddStyleToDoc(document.MainDocumentPart.Document.MainDocumentPart, styleId, styleName, styleRunProperties, document);
Paragraph p = new Paragraph();
ParagraphProperties pp = new ParagraphProperties();
pp.ParagraphStyleId = new ParagraphStyleId() { Val = styleId };
pp.SpacingBetweenLines = new SpacingBetweenLines() { After = "0" };
ParagraphStyleId paragraphStyleId1 = new ParagraphStyleId() { Val = "ListParagraph" };
NumberingProperties numberingProperties1 = new NumberingProperties();
NumberingLevelReference numberingLevelReference1 = new NumberingLevelReference() { Val = numLvlRef };
NumberingId numberingId1 = new NumberingId() { Val = numIdVal }; //Val is 1, 2, 3 etc based on your numberingid in your numbering element
numberingProperties1.Append(numberingLevelReference1); Indentation indentation1 = new Indentation() { FirstLineChars = 0 };
numberingProperties1.Append(numberingId1);
pp.Append(paragraphStyleId1);
pp.Append(numberingProperties1);
pp.Append(indentation1);
p.Append(pp);
Run r = new Run();
Text t = new Text(headingText) { Space = SpaceProcessingModeValues.Preserve };
r.Append(t);
p.Append(r);
document.MainDocumentPart.Document.Body.Append(p);
}
public static void AddStyleToDoc(MainDocumentPart mainPart, string styleid, string stylename, StyleRunProperties styleRunProperties, WordprocessingDocument document)
{
StyleDefinitionsPart part = mainPart.StyleDefinitionsPart;
if (part == null)
{
part = AddStylesPartToPackage(mainPart);
AddNewStyle(part, styleid, stylename, styleRunProperties);
}
else
{
if (IsStyleIdInDocument(mainPart, styleid) != true)
{
string styleidFromName = GetStyleIdFromStyleName(document, stylename);
if (styleidFromName == null)
{
AddNewStyle(part, styleid, stylename, styleRunProperties);
}
else
styleid = styleidFromName;
}
}
}
public static string GetStyleIdFromStyleName(WordprocessingDocument doc, string styleName)
{
StyleDefinitionsPart stylePart = doc.MainDocumentPart.StyleDefinitionsPart;
string styleId = stylePart.Styles.Descendants<StyleName>()
.Where(s => s.Val.Value.Equals(styleName) &&
(((Style)s.Parent).Type == StyleValues.Paragraph))
.Select(n => ((Style)n.Parent).StyleId).FirstOrDefault();
return styleId;
}
public static StyleDefinitionsPart AddStylesPartToPackage(MainDocumentPart mainPart)
{
StyleDefinitionsPart part;
part = mainPart.AddNewPart<StyleDefinitionsPart>();
DocumentFormat.OpenXml.Wordprocessing.Styles root = new DocumentFormat.OpenXml.Wordprocessing.Styles();
root.Save(part);
return part;
}
public static bool IsStyleIdInDocument(MainDocumentPart mainPart, string styleid)
{
DocumentFormat.OpenXml.Wordprocessing.Styles s = mainPart.StyleDefinitionsPart.Styles;
int n = s.Elements<DocumentFormat.OpenXml.Wordprocessing.Style>().Count();
if (n == 0)
return false;
DocumentFormat.OpenXml.Wordprocessing.Style style = s.Elements<DocumentFormat.OpenXml.Wordprocessing.Style>()
.Where(st => (st.StyleId == styleid) && (st.Type == StyleValues.Paragraph))
.FirstOrDefault();
if (style == null)
return false;
return true;
}
private static void AddNewStyle(StyleDefinitionsPart styleDefinitionsPart, string styleid, string stylename, StyleRunProperties styleRunProperties)
{
DocumentFormat.OpenXml.Wordprocessing.Styles styles = styleDefinitionsPart.Styles;
DocumentFormat.OpenXml.Wordprocessing.Style style = new DocumentFormat.OpenXml.Wordprocessing.Style()
{
Type = StyleValues.Paragraph,
StyleId = styleid,
CustomStyle = false
};
style.Append(new StyleName() { Val = stylename });
style.Append(new BasedOn() { Val = "Normal" });
style.Append(new NextParagraphStyle() { Val = "Normal" });
style.Append(new UIPriority() { Val = 900 });
styles.Append(style);
}
【问题讨论】:
-
据我所知,这段代码只定义了 1 个(第一个)编号级别。如果要使用三个编号级别,则必须定义所有级别,包括要使用前一个编号级别的哪些信息。我的建议是使用 UI 中的工具在新的 Word 文档中创建这样的样式。保存、关闭并在 Open XML SDK Productivity Tool 中打开。这将为您提供创建文档所需的代码。
-
或者,或者,保存起点文档,创建样式,将其保存为不同的文件名。在生产力工具中打开第一个,然后对第二个使用比较功能。这将为您提供从第一个文档创建第二个文档的代码。
-
@CindyMeister,不幸的是,仅靠样式无法完成这项工作。您需要一个编号定义部分,其中指定了多级列表。使用 Microsoft Word,您可以创建 (1) 多级列表并将每个所需级别链接到样式或 (2) 列表样式。在这两种情况下,多级列表的关键信息(例如编号格式)都在编号定义部分中定义。
-
@ThomasBarnekow 在我的书中,编号定义是样式。查看生产力工具会准确地显示出某人需要哪些
Part类型。而且...在 Stack Overflow 上,如果您已经回答了一个问题(或知道网站上的答案),则应将问题标记/关闭为“重复”,而不是通过链接简要回答。