【问题标题】:vsto Range.Find on empty single cell selection returns range outside of the cellvsto Range.Find 空单个单元格选择返回单元格外的范围
【发布时间】:2023-03-30 02:26:01
【问题描述】:

在我的 VSTO 加载项项目中,如果我选择一个空单元格(如 F11)并在该范围内运行 find 以获取任何值,它似乎会搜索整个工作表并在我期望的时候返回范围 A1:E10返回空值。下面是我选择的单元格的图像。

我通过选择访问这个范围,当我在调试时检查时,它有 6 列和 11 行,这是我选择的。当我试图在这个范围内找到任何东西时,我希望我应该得到一个空值,但我得到的是 E10 的值,这是没有意义的。

这是我的 c# 代码,第一部分获取一个选择并遍历 范围区域,在单个选择的情况下只有 1 个区域。

即使 F11 是唯一选择的单元格,最后的 val1 和 val2 的值都是 3197077000。

using Microsoft.Office.Interop.Excel;
using System;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;

namespace ExcelAddIn1
{
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private void button1_Click_1(object sender, EventArgs e)
        { 
            Excel.Range selection = Globals.ThisAddIn.Application.Selection;

            if (null != selection)
            {
                var sheet = selection.Worksheet;
                var book = (Excel.Workbook)sheet.Parent;

                var areasCount = selection.Areas.Count;

                for (int i = 1; i <= areasCount; i++)
                {
                    var area = selection.Areas[i];

                    var test = area.Value;
                    var testCount = area.Count;
                    var testRow = area.Row;
                    var testCol = area.Column;

                    Excel.Range lastCellInLastRow = area.Find(
                    "*",
                    Type.Missing,
                    XlFindLookIn.xlFormulas,
                    XlLookAt.xlPart,
                    XlSearchOrder.xlByRows,
                    XlSearchDirection.xlPrevious,
                    false,
                    Type.Missing,
                    Type.Missing);

                    Excel.Range lastCellInLastCol = area.Find(
                        "*",
                        Type.Missing,
                        XlFindLookIn.xlFormulas,
                        XlLookAt.xlPart,
                        XlSearchOrder.xlByColumns,
                        XlSearchDirection.xlPrevious,
                        false,
                        Type.Missing,
                        Type.Missing);

                    var val1 = lastCellInLastCol.Value;
                    var val2 = lastCellInLastRow.Value;

                }
            }
        }
    }
}

当我在 VBA 中做同样的事情时,按预期在 F11 上运行 find 时得到一个 null

Option Explicit
Public Sub SelectionTest()
    Dim selection As Variant
    Dim rng As Range
    Dim UsedRange As Variant
    Dim lastCell As Range

    Set selection = Application.selection

    Dim area As Range

    Debug.Print "selection columns " & selection.Columns.Count

    Dim finalRng As Range
    Dim finalArr As Variant

    For Each area In selection.Areas
        Debug.Print "single rng columns " & area.Columns.Count
        Set lastCell = area.Find(What:="*", After:=area.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
                        xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False)

        Set lastCell = area.Find(What:="*", After:=area.Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
                        xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)

        Debug.Print lastCell

    Next

End Sub

【问题讨论】:

  • 您在问题中添加了很多代码;其中很多是指我们大多数人没有或不知道它们是什么的图书馆。您能否创建一个minimal reproducible example,清楚地反映问题情况 - 仅使用标准 VSTO - 以便我们可以有效地调查?
  • @CindyMeister 更新为在一个较小的示例中使用标准 VSTO 库。

标签: c# excel com range vsto


【解决方案1】:

简短回答:Interop / Range.Find 可能不可靠。尽可能少使用 Interop。

更长的答案:我在实践中注意到关于Range.Find 的不可靠的事情之一是它似乎对之前最后一次搜索的内容有记忆。这可能是也可能不是这里的问题,但如果我是你,我不会费心去想办法,因为你可以通过以下方式解决你的问题:

  • 将整个范围作为二维数组读入内存
  • 将数组元素转换为字符串
  • 使用强大的 C# 正则表达式库和嵌套的 for 循环来搜索数组

需要做更多的工作,但摆脱互操作这一不可靠的基础是值得的。这里有一些代码可以帮助您开始阅读范围:

public string[,] ReadValues(Range range)
{
    return ConvertToStringArray2D(GetArray(range, () => range.Value2));
}

private string[,] ConvertToStringArray2D(Array values)
{
    string[,] retArray = new string[values.GetLength(0), values.GetLength(1)];

    // loop through the 2-D System.Array and populate the 1-D String Array
    for (int row = 1; row <= values.GetLength(0); row++)
    {
        for (int col = 1; col <= values.GetLength(1); col++)
        {
            if (values.GetValue(row, col) == null)
            {
                retArray[row - 1, col - 1] = "";
            }
            else
            {
                retArray[row - 1, col - 1] = values.GetValue(row, col).ToString();
            }
        }
    }

    return retArray;
}

private Array OneBasedSingletonArray2D()
{
    return Array.CreateInstance(typeof(Object), new int[] { 1, 1 }, new int[] { 1, 1 });
}       

private Array GetArray(Range range, Func<object> dataProducer)
{
    if (range.Cells.Count == 0)
    {
        return Array.CreateInstance(typeof(Object), 0, 0);
    }
    if (range.Cells.Count == 1)
    {
        //Creating a 1-based array to fit with Excel's 1-based indexing
        Array retArray = OneBasedSingletonArray2D();
        retArray.SetValue(dataProducer.Invoke(), 1, 1);
        return retArray;
    }
    else
    {
        return (Array)dataProducer.Invoke();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多