OpenXml SDK学习笔记(3):设置样式

看日志的时间间隔基本就知道我的开发时间了,就样式这一点做了我近1个半小时。所谓设置样式,针对到Word里,大致有这样的内容:

 

 

 你把平时用不到的内容一去,那么必须要做的功能就列出来了:

字体:设置字体,设置字号,粗体,斜体,下划线

段落:设置对齐方式,设置首行缩进,设置段前,设置段后

这里我特意分了两行。可以看到第一行,是在Word的是“字体”的设置。第二行则是在“段落”这个窗口里设置。针对到代码里,很容易可以发现,其实第一个就是针对Run,第二个就是针对Paragraph来的。所以,在WordprocessingML里,也有专门用来修饰这两个的标签,也就是RunProperties和ParagraphProperties。他们应当是各自母标签的第一个子标签。并且在一个段落和连续文本内,不应该出现两次。

所以,可以根据这样的代码初始化一个ParagraphProperties

1 public override void InitializeElement()
2 {
3     Properties = Run.GetFirstChild<RunProperties>();
4     if (Properties == null)
5     {
6         Properties = new RunProperties();
7         Run.PrependChild(Properties);
8     }
9 }

这里必须先找元素再加入,否则如果出现了两个就不太好了。另外,由于大部分组件都有对应的Properties对象,所以这个初始化元素函数就加到CompositeElementBase这个类里,以防之后遗漏。之后就是一个无聊的工作了,按照规定把所有代码都敲完就完整了。在这里,有几个注意点:

1. 处理字号的时候,字号的点数和保存的值的关系是:value = size * 2。并且,这个数是要小于1600的。当然具体的值是1600多一些,记的不是很清楚了,取1600绝对没有问题。所以,字号就是这样的:

public override CompositeElementBase SetFontSize(int sizePoint)
{
    if (sizePoint < 0 || sizePoint > 800)
    {
        throw new InvalidOperationException("字体大小必须大于0,并且小于800");
    }

    DefaultRunProperties.FontSize = new DocumentFormat.OpenXml.Wordprocessing.FontSize()
    {
        Val = (sizePoint * 2).ToString()
    };
    return SetPropertiesToChildren();
}

2. 一些常用的字号可以用枚举,那由于枚举对应的值只能是int。而常用字号里有几个是有 0.5 的。所以,直接存双倍数就可以。

public enum FontSize : int
{
    ch初号 = 84,
    xc小初 = 72,
    yh一号 = 52,
    xy小一 = 48,
    eh二号 = 44,
    xe小二 = 36,
    sh三号 = 32,
    xs小三 = 30,
    sh四号 = 28,
    xs小四 = 24,
    hh五号 = 21,
    xh小五 = 18,
    lh六号 = 15,
    xl小六 = 13,
    qh七号 = 11,
    bh八号 = 10
}

这里,写中文是为了方便识别。前面带两个拼音是为了打字方便。

3. 字体分为中文字体和西文字体,这两个可以分开设置。Ascii就是西文字体,EastAsia就是中文字体。

public override CompositeElementBase SetFontFamily(string zwFamily, string asciiFamily)
{
    DefaultRunProperties.RunFonts = new RunFonts()
    {
        Ascii = asciiFamily,
        EastAsia = zwFamily
    };
    return SetPropertiesToChildren();
}

4. 下划线是通过一个枚举设置的:UnderlineValues。这个枚举可以查看文档:https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.wordprocessing.underlinevalues 。但是在编码的时候,为了可以让最终使用者完全不认识 DocumentFormat.OpenXml.Wordprocessing 这个命名空间,所以,要通过代码对其进行封装。那自己写一个枚举,然后转换一下就行了。注意,这里绝对不推荐图省事直接用“UnderlineValues”,如果直接用了这个东西,那就封了个寂寞。

 

5. 水平对齐方式不是TextAlignment,这个是垂直对齐。水平对齐的那个属性叫“Justification”对应枚举的MSDN文档是:https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.wordprocessing.justificationvalues 。不过,我Html做的比较多,所以函数还是用SetAlign了。同样的,这个枚举也要封装。

 

6. 在Word里,缩进其实有四种:左缩进,右缩进,首行缩进和悬挂缩进。对应的MSDN文档:https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.wordprocessing.indentation 。我常用的只有首行缩进两字符,所以我只留了这个函数:

public override CompositeElementBase SetFirstLineIndent(float chars = 2)
{
    if (chars < 0)
    {
        throw new InvalidOperationException("参数chars必须大于 0");
    }

    Properties.Indentation = new Indentation()
    {
        FirstLineChars = (int)(chars * 100)
    };
    return this;
}

在这里,“FirstLineChars”这个属性的值是字符数乘以100的整数。

 

7. 段前,段后间距以及行距的 MSDN文档是:https://docs.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.wordprocessing.spacingbetweenlines 。在这个对象里可以设置上述三种值。间距的单位“磅”在文档里写的是“twentieths”,也就是20分之一。即如果写了10磅。那这个值就是 200,乘以20的关系。而行距一般使用倍数。几倍行距则是 240的多少倍,比如单倍行距,则Line设置为240,两倍行距就是480这样。如果要设置成“最小值”或者“固定值”则需要配合LineRule这个属性。这是一个枚举,也非常简单相信一看就懂。同样的,如果代码要用,那就建议封装一下。

public override CompositeElementBase SetLineHeight(double times)
{
    var sbl = Properties.SpacingBetweenLines;
    if (sbl == null)
    {
        sbl = new SpacingBetweenLines();
        Properties.SpacingBetweenLines = sbl;
    }
    sbl.Line = (times * 240).ToString();
    return this;
}

public override CompositeElementBase SetLineBefore(int pt)
{
    var sbl = Properties.SpacingBetweenLines;
    if (sbl == null)
    {
        sbl = new SpacingBetweenLines();
        Properties.SpacingBetweenLines = sbl;
    }
    sbl.Before = (pt * 20).ToString();
    return this;
}

public override CompositeElementBase SetLineAfter(int pt)
{
    var sbl = Properties.SpacingBetweenLines;
    if (sbl == null)
    {
        sbl = new SpacingBetweenLines();
        Properties.SpacingBetweenLines = sbl;
    }
    sbl.After = (pt * 20).ToString();
    return this;
}

 

最后,改一下Main函数,就完成啦!对比一下需求,这个标题是完!全!一!样!

 

posted @ 2021-11-10 18:22  bluesky234  阅读(1308)  评论(0编辑  收藏  举报