本帖最后由 Joestar.Xu 于 2025-4-10 14:38 编辑
您好,关于这个问题,主要是要弄清楚"TemplateOptions.ReferenceExpandPolicy"的用途,以及为什么要设置这样一个Option。
我们先理解GcExcel模板引擎在生成一个公式时,它是如何调整单元格引用的。假设有这样一个数据源:
有这样一个模板:
这个模板展开后,C5单元格中的公式应该变成什么样子呢?
可以肯定的是,它不能再是C4, 因为C4这个单元格会展开成多个单元格,它应该是这多个单元格共同构成的一个区域。这个区域的大小不是固定的,它取决于C4这个单元格能扩展出来的单元格数量,以及它扩展的方向。
而且,我们还知道,这里面有两家公司。每家公司都会有一个公式来计算总销售额,两个公式不能打架。因此,当我们根据模板公式=sum(C4)生成报表的公式时,并不是把模板C4单元格展开的所有单元格都拿进来考虑,而是要筛选,只选择和当前公司有关的那一部分单元格。
最后,这个报表展开后是这样:
我们可以看到,在展开的报表中,生成了两个公式,
一个在C9单元格,内容是“= SUM (C4:C8)”,一个在C16单元格,内容是“=SUM(C13:C15)”。
GcExcel的模板引擎究竟是怎么计算出区域C4:C8和C13:C15的呢?
1. 首先,模板引擎会根据父子关系把所有的单元格构造成一棵树,树的根节点是worksheet。为了简化,我们只挑选我们关注的这几个单元格,出来的树形图是这样(图中括号表示当前单元格对应的模板单元格)。
2. 模板引擎需要为C9(C5)和C16(C5)这两个单元格生成公式,因为这两个单元格是模板单元格C5扩展来的,它上面有公式=sum(C4)。
3. 模板引擎发现公式中引用了C4单元格,它需要去找C4单元格扩展出来的单元格。但它不能把所有C4扩展出来的单元格都找出来,而是要找和当前单元格有关的单元格。当模板引擎为C9(C5)生成公式时,它会先向上找C5和C4的父单元格C2,于是会找到C2(C2)这个单元格,然后向下找所有c4扩展出来的单元格,于是会找到c4(c4),c5(c4),c6(c4),c7(c4),c8(c4), 这些单元格构成的区域是C4:C8。
4. 最终,模板引擎为c9(C5)生成一个公式:=sum(C4:C8),同理,也为C11(c2)生成一个公式:=sum(C13:C15)。
经过上面的分析,我们可以看出,模板引擎在生成公式的时候,它会考虑单当前单元格和被引用单元格的关系,他们共同的父单元格是一个关键因素,它是挑选被引用单元格的依据。
这是GcExcel 的模板引擎在生成公式时的默认策略,这个策略在大部分情况下都符合您的期望,但是在有些情况下,和您的期望不同,比如您这个模板。
我们看看这个模板的特殊性,我们只挑选我们需要关注的几个单元格,B8,C8,M8,N8,BO8,CC8,其它无关的单元格隐藏掉
下面是这几个单元格的内容
| | | | | {{ds_4.c37(S=None,C=None)}} | | {{==IFERROR(RANK(N8,N:N),"")(S=None,C=C8)}} | | {{==IFERROR(BO8/CC8-1,"")(S=None,C=B8)}} | | {{=SUM(ds_5.c0)(S=None,C=B8)}} | | {{=SUM(ds_5.c13)(S=None,C=B8)}} |
需要注意:N8,BO8,CC8的父单元格是B8, M8的父单元格是C8,C8没有父单元格,可以认为它的父是Worksheet,B8的父也是worksheet,因为前面的A8是空的。下面是模板单元格的父子关系图。
模板单元格M8上有一个公式: =IFERROR(RANK(N8,N:N),""), 当M8展开后,它会生成很多单元格,比如:M8(M8),M9(M8),M10(M8)…,模板引擎需要为每一个单元格生成一个公式,公式中的N8这个单元格应该变成什么呢?
根据我们前面介绍,模板引擎需要从单元格树中的所有N8展开的单元格中,挑选和当前单元格有关系的单元格。但发现,M8和N8没有共同的父,他们最近的共同的祖先是Worksheet, 于是,模板引擎认为,worksheet下面所有的N8生成的单元格,都和当前单元格有关,于是就生成了公式:
=IFERROR(RANK(N8:N17,N:N),"")。
这个公式不是我们期望的,造成这个问题的原因是M8的父单元格和其它父单元格不一样,如果M8的父单元格也是B8, 生成的公式就是我们期望的。
不知道为什么要这样的设计模板?B8和C8都是门店,但它们内容不同,N8,BO8,CC8是基于B8的门店分类,而M8基于C8的门店分类,把它们用一个公式关联起来,感觉逻辑上不合理。
当然,现实中有各种各样的需求,只能说,这种需求,模板引擎默认的公式扩展策略无法满足需要,需要采用另一种策略。
GcExcel提供了一个选项"TemplateOptions.ReferenceExpandPolicy",它可以改变公式中单元格引用的扩展策略,如果把它设置为”Excel”,它就会按照Excel中复制/粘贴的策略走。
Excel中对公式的复制/粘贴策略是怎么样的呢?它不会考虑被引用单元格的变化,只考虑当前单元格的位置,它有这样两条原则:
1. 绝对引用保持不变,比如$A$1这样的单元格,不管公式复制到哪儿都不变。
2. 相对引用不改变大小,只改变位置,当前单元格位置偏移了多少,那么引用的单元格位置也偏移多少。
对于这个模板,刚好Excel 这种复制策略能满足需求,因此需要设置选项"TemplateOptions.ReferenceExpandPolicy"为”Excel”
|