加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 此命令至少需要两行源数据

发布时间:2020-12-16 00:05:15 所属栏目:百科 来源:网络整理
导读:我收到此错误: This command requires at least two rows of source data. You cannot use the command on a selection in only one row. Try the following:- If you're using an advanced filter,select a range of cells that contains at least two row
我收到此错误:

This command requires at least two rows of source data. You cannot use the command on a selection in only one row. Try the following:

- If you're using an advanced filter,select a range of cells that contains at least two rows of data. Then click the Advanced Filter command again.
- I you're creating a PivotTable,type a cell reference or select a range that includes at least two rows of data

间歇性地在这行代码上:

xlWorkBook.RefreshAll();

有两个工作表.一个有一个数据透视表,一个有原始数据.有时只有一行数据.对于多行数据,上面的代码行始终有效;但是,对于只有1行数据,上面的代码有时会起作用,有时我会收到上面的错误消息.

除此之外,包含数据透视表的工作表不会刷新;但是,如果我重新打开文件,它也不会刷新,除非我手动显式刷新它.

这里发生了什么?为什么我有时会收到此错误?

非常感谢你的指导.

如果有帮助,我包括整个方法:

private void SortandCreateFile(string column,string email,string emailStartPos) {
    string replacetext = "";

    try {
        var valueRange = xlWorkSheet.get_Range(column + emailStartPos,column + range.Rows.Count.ToString());
        var deleteRange = valueRange;
        xlApp.Visible = false;
        int startpos = 0;
        int endPos=0;
        bool foundStart = false;

        Excel.Range rng = xlWorkSheet.get_Range(column + "1",column + range.Rows.Count.ToString());

        string tempstring = "d";
        int INTemailStartPos = Convert.ToInt16(emailStartPos);

        for (int rCnt = INTemailStartPos; rCnt <= rng.Count; rCnt++) {
            Excel.Range cell = (Excel.Range)rng[rCnt,1];

            try {
                if (cell.Value2 != null)
                    tempstring = cell.Value2.ToString();
                else {
                    startpos = rCnt;
                    releaSEObject(cell);  /////////
                    break;
                }
            }
                catch (Exception ee)
            {
            MessageBox.Show(ee.ToString());
        }
        //grab the text from column link texdtbox
        Excel.Range rngLinkColumn;
        Excel.Range replacetextcell=null;

        if (FormControls.ColumnLink.Length > 0) {
            rngLinkColumn = xlWorkSheet.get_Range(FormControls.ColumnLink + "1",FormControls.ColumnLink + range.Rows.Count.ToString());
            replacetextcell = (Excel.Range)rngLinkColumn[rCnt,1];
        }    
        //locate email
        if (cell.Value2.ToString() == email ) {
            //we found the starting position of the email we want!
            //this will tell us which row of data to start from
            startpos = rCnt;

            if (FormControls.ColumnLink.Length > 0)
                replacetext = replacetextcell.Value2.ToString();
            releaSEObject(cell);  /////////
            break;
        }
        releaSEObject(cell);
    }
    int foundstartminusONE = startpos - 1;
    int rngcount = rng.Count + INTemailStartPos;

    //delete everything from the top UNTIL the row of the email address that we need
    if (startpos != INTemailStartPos) {
        deleteRange = xlWorkSheet.get_Range(column + INTemailStartPos.ToString() + ":" + "CF" + foundstartminusONE.ToString(),Type.Missing);
        deleteRange = deleteRange.EntireRow;
        deleteRange.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
    }

    for (int rCnt = INTemailStartPos; rCnt <= rng.Count; rCnt++) {
        Excel.Range cell = (Excel.Range)rng[rCnt,1];

        try {
            if (cell.Value2 != null )
                tempstring = cell.Value2.ToString();
            else {
                endPos = rCnt - 1;
                releaSEObject(cell);////////
                break;
            }
        }
        catch (Exception ee) {
            //MessageBox.Show(ee.ToString());
        }    
        //locate email
        if (cell.Value2.ToString() != email ) {
            //we found where the last email address is that we need
            //this is where the issue is occurring i think with the deleting the last row
            endPos = rCnt;
            releaSEObject(cell);////////
            break;
        }
        releaSEObject(cell);
    }

    //delete all the stuff AFTER the email address that we need
    if (endPos != 0) {
        deleteRange = xlWorkSheet.get_Range(column + endPos + ":" + "CF" + rngcount.ToString(),Type.Missing);
        deleteRange = deleteRange.EntireRow;
        deleteRange.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
    }

    //when the user opens the excel file,we want the focus to be here
    var rangehome = xlWorkSheet.get_Range(FormControls.FocusOn,FormControls.FocusOn);
    xlWorkSheet.Activate();
    rangehome.Select();

    string filename = xlWorkBook.Path + @"" + email + ".xlsx";
    string fileSubstring = filename.Substring(0,filename.IndexOf(".xlsx"));
    string randomfileString = Guid.NewGuid().ToString("N").Substring(0,10) + ".xlsx";
    string targetfilenameRename = fileSubstring + randomfileString;

    //((Excel.Worksheet)this.Application.ActiveWorkbook.Sheets[FormControls.WorksheetFocus]).Activate();
    //((Excel.Worksheet)Excel.Application.ActiveWorkbook.Sheets[1]).Activate();  

    Excel.Worksheet xlWorkSheetFocus = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(FormControls.WorksheetFocus);
    xlWorkSheetFocus.Activate();
    xlWorkBook.SaveAs(targetfilenameRename,Excel.XlFileFormat.xlWorkbookDefault,Type.Missing,false,Excel.XlSaveAsAccessMode.xlNoChange,Excel.XlSaveConflictResolution.xlLocalSessionChanges,Type.Missing);

    try {
        xlWorkBook.RefreshAll();
    }
    catch { }
        xlWorkBook.Save();
        string targetfile = xlWorkBook.Path + @"" + FormControls.FileName + " - "
                    + email.Substring(0,email.IndexOf("@")) + ".xlsx";
        System.IO.File.Copy(targetfilenameRename,targetfile,true);

        string body = FormControls.eMailBody;
        body = body.Replace("%replacetext%",replacetext);
        //replace %replacetext% in body
        string targetfileSubstring = targetfile.Substring(0,targetfile.IndexOf(".xlsx"));
        string randomString = Guid.NewGuid().ToString("N").Substring(0,10)+".xlsx";
        string targetfileRename = targetfileSubstring+randomString;

        while (true) {
            try {
                SendEmail(targetfile,email,FormControls.eMailSubject,body,FormControls.eMailFrom);                                  
            }
            catch (Exception ee) {
                MessageBox.Show(ee.ToString());
                continue;
            }

            // all is good
            break;
        }
        releaSEObject(valueRange);
        releaSEObject(deleteRange);
        File.Copy(targetfile,targetfileRename,true);
    }
    catch (Exception e) {
        MessageBox.Show(e.ToString());
    }
    finally {
        //DisposeMe();
        // Release all COM RCWs.
        // The "releaSEObject" will just "do nothing" if null is passed,// so no need to check to find out which need to be released.
        // The "finally" is run in all cases,even if there was an exception
        // in the "try". 
        // Note: passing "by ref" so afterwords "xlWorkSheet" will
        // evaluate to null. See "releaSEObject".
        releaSEObject(range);
        releaSEObject(xlWorkSheet);
        releaSEObject(xlWorkBook);
        // The Quit is done in the finally because we always
        // want to quit. It is no different than releasing RCWs.
        if (xlApp != null) {
            xlApp.Quit();
        }
        releaSEObject(xlApp);
    }
}

解决方法

我可以使用数据透视表复制此错误的唯一方法是尝试在没有列标题的范围内创建一个,就像Stephan1010的答案截图一样.

在GetPivotData Excel函数中,透视字段由它们的名称引用(= GETPIVOTDATA(“EmailAddress”,$A $3));因此,禁止不具备它们的数据源是有意义的.

当您选择范围$A $1:$C $1并格式化为表格(来自功能区)时,解决方案是在ListObject而不是Range上进行数据透视 – 结果表格将超过$A $1: $C $2;第一行的内容成为列标题,第二行是有效的空记录.有趣的是,无论您是否检查“我的表有标题”复选框,都会发生这种情况(2行跨度)(数据将移动到第一行,表格将包含默认的“Column1” – “Column2” “ – ”如果清除复选框,则为Column3“标题.

换句话说,ListObject始终是数据透视表的有效数据源,而Range可能不包含足够的行.此外,如果您没有列标题并且创建范围为$A $1:$C $2的数据透视表,则$A $1:$C $1的记录将用作列标题,这意味着第一条记录将丢失.

从你提供的代码我可以假设数据透视表已经存在并连接到包含宏的模板工作簿中的某个[named?]范围.将范围转换为表格可能与从Ribbon中选择格式作为表格一样简单.然后,您可以使用这样的代码删除所有不必要的行,同时仍保留数据透视表的有效数据源:

public void DeleteExtraTableRows(string emailAddress,Excel.ListObject table)
    {
        try
        {
            var rowIndex = 0;
            var wasDeleted = false;
            while (rowIndex <= table.ListRows.Count)
            {
                if (!wasDeleted) rowIndex++;
                var row = table.ListRows[rowIndex];

                var range = (Excel.Range)row.Range.Cells[1,1];
                var value = range.Value2;

                if (value != null && !string.Equals(emailAddress,value.ToString()))
                {
                    row.Delete();
                    wasDeleted = true;
                }
            }
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message + "nn" + e.StackTrace);
        }
    }

还有可能在循环的if(cell.Value2.ToString()== email)条件中找不到电子邮件,这最终会删除范围内的所有行 – 即使唯一的差异是在内嵌值的结束.使用上面的代码,即使删除了所有电子邮件地址,数据源仍然是与其连接的数据透视表的有效数据源.

编辑:
在Excel中,通过选择有问题的范围并单击“主页”选项卡中的“格式为表格功能”按钮,将Range转换为ListObject.或者你可以创建一个这样的:

var range = ((Excel.Range)(worksheet.Range[worksheet.Cells[1,1],worksheet.Cells[3,1]]));
            var table = worksheet.ListObjects.Add(SourceType: Excel.XlListObjectSourceType.xlSrcRange,Source: range,XlListObjectHasHeaders: Excel.XlYesNoGuess.xlYes);
            table.TableStyle = "TableStyleMedium3";

在代码中,您可以使用ListObjects属性访问工作表上的所有ListObject:

var worksheet = (Excel.Worksheet) Globals.ThisAddIn.Application.ActiveSheet;
        var tables = worksheet.ListObjects;

然后,您可以使用几种不同的方式访问特定的ListObject /表:

var myTable = tables[1];
        var myTable = tables.Item["Table1"];
        var myTable = tables.OfType<Excel.ListObject>().FirstOrDefault(t => t.Name == "Table1");

当从表中添加行时,它引用的实际范围将相应地扩展;使用myTable.Range访问相关范围.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读