zblongman 发表于 2012-11-12 15:51:00

如何处理不直接被Spread支持的公式形式?

在导入的Excel文件的G58单元的公式为“=SLOPE(E58:E62,LN(D58:D62))”
现象(如下图所示):


经分析,发现是导入的文件中的公式SLOPE(E58:E62,LN(D58:D62))无法被Spread进行解析。
我的问题:
      1、我自己是否可以通过扩展公式API来代替原用公式的计算行为?如果可以,大致思路应该是什么样的?
      2、如果第1种方式不行,那么我该怎么才能让Spread达到的Excel的显示结果?


谢谢!!!

ZenosZeng 发表于 2012-11-12 18:06:00

zblongman 你好

你的这个问题正在处理中,明天给你回复。

zblongman 发表于 2012-11-12 20:15:00

dof 辛苦了 谢谢!!

ZenosZeng 发表于 2012-11-13 15:26:00

zblongman 你好

非常抱歉,让你久等了。

你遇到的这个问题时Spread和Excel中的LN公式实现有些差异照成的,在Excel中LN可以接受一个单元格范围作为参数,而Spread中的LN只识别单元格范围中的第一个单元格的值。

比如有这样的公式设置 ==SLOPE(B1:B6,C1:C6) ,可以用以下解决方案:
1、给A1单元格设置公式:=SLOPE(B1:B6,C1:C6)
2、给C1:C6设置LN(D1)的公式

zblongman 发表于 2012-11-13 16:44:00

dof 你好!
谢谢你的回答!
但是这里有一个问题,就是Excel表是客户自己事先定义好的,不是我们设计的,我们这里是想解决这种不兼容的问题。
换言之,我想做的是自己开发程序解决这个公式差异问题,比如用自定义的公式替换Spread控件中已有的公式,这样可行吗?我该如何做?

ZenosZeng 发表于 2012-11-13 17:53:00

zblongman 你好

我这边正在尝试使用自定义公式来解决该问题,已有消息我会立即给你回复。

zblongman 发表于 2012-11-13 20:20:00

dof 你好
辛苦你你们了,谢谢了!

ZenosZeng 发表于 2012-11-14 09:53:00

你好!

通过自定义公式可以实现该需求,具体代码如下:
    public partial class MainPage : UserControl
    {
      public MainPage()
      {
            InitializeComponent();

            gcSpreadSheet1.Sheets.Cells.Value = 1;
            gcSpreadSheet1.Sheets.Cells.Value = 2;
            gcSpreadSheet1.Sheets.Cells.Value = 3;
            gcSpreadSheet1.Sheets.Cells.Value = 9;

            gcSpreadSheet1.Sheets.Cells.Value = 5;
            gcSpreadSheet1.Sheets.Cells.Value = 6;
            gcSpreadSheet1.Sheets.Cells.Value = 7;
            gcSpreadSheet1.Sheets.Cells.Value = 5;

            gcSpreadSheet1.AddCustomFunction(new CalcCSLOPEFunctionInfo());
            gcSpreadSheet1.AddCustomFunction(new CLNFunctionInfo());

            gcSpreadSheet1.Sheets.SetFormula(0, 0, "CSLOPE(B1:B4,CLN(C1:C4))");
      }
    }

    public class CalcCSLOPEFunctionInfo : GrapeCity.CalcEngine.Functions.CalcSlopeFunction
    {
      public override string Name
      {
            get
            {
                return "CSLOPE";
            }
      }

      public override object Evaluate(object[] args)
      {
            // 将第二个参数封装成 CCalcArray 类型,并传作为调用基类 Evaluate 方法的参数
            if (args is object[,])
            {
                CCalcArray array = new CCalcArray(args as object[,]);
                args = array;
            }

            return base.Evaluate(args);
      }
    }

    public class CLNFunctionInfo : GrapeCity.CalcEngine.Functions.CalcFunction
    {
      public override string Name
      {
            get
            {
                return "CLN";
            }
      }

      public override object Evaluate(object[] args)
      {
            if (args is CalcReference)
            {
                // 如果传递的是单元格范围的引用,使用使用以下方法进行计算
                CalcReference array = (CalcReference)args;
                int rowCount = array.GetRowCount(0);
                int columnCount = array.GetColumnCount(0);
                object[,] result = new object;
                for (int i = 0; i < rowCount; i++)
                {
                  for (int j = 0; j < columnCount; j++)
                  {
                        object value = array.GetValue(0, i, j);
                        if (value is CalcError)
                        {
                            result = value;
                        }
                        else
                        {
                            result = Math.Log(Convert.ToDouble(value.ToString()));
                        }
                  }
                }
                return result;
            }
            else
            {
                return Math.Log(Convert.ToDouble(args.ToString()));
            }
      }

      public override int MaxArgs
      {
            // 最多接收一个单元格引用范围
            get { return 1; }
      }

      public override int MinArgs
      {
            // 至少需要一个单元格引用范围
            get { return 1; }
      }

      public override bool AcceptsReference(int i)
      {
            // 允许接收单元格引用的参数类型
            return true;
      }
    }

    // 自定义 CalcArray 类型
    public class CCalcArray : CalcArray
    {
      object[,] items;

      public CCalcArray(object[,] items)
      {
            this.items = (object[,])items.Clone();
      }
      public override int RowCount
      {
            get { return items.GetLength(0); }
      }
      public override int ColumnCount
      {
            get { return items.GetLength(1); }
      }
      public override object GetValue(int row, int column)
      {
            return items;
      }
    }

源码下载:

zblongman 发表于 2012-11-19 09:06:00

谢谢 dof
我还有点疑问,我另外开个帖子吧!

ZenosZeng 发表于 2012-11-19 17:49:00

OK,我在另外一个帖子给你回复。
页: [1]
查看完整版本: 如何处理不直接被Spread支持的公式形式?