我尝试在Excel和C#之间传输一些数据。为此,我编写了一个简单的C#类,其中包含一个用于设置和获取数据的属性。
[Guid("xxx")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Vector
{
private object[,] _values;
public object[,] ExcelValues
{
get { ... }
set { ... }
}
}
在VBA中获取ExcelValues属性效果很好,但无法在VBA中设置它。如果我尝试设置属性,则VBA代码无法编译:
Dim values As Variant
With myRange
' typo: Set values = Range(.Offset(0, 0), .Offset(100, 0))
values = Range(.Offset(0, 0), .Offset(100, 0))
End With
Dim data As New Vector
' this doesn't compile
data.ExcelValues = values
' this works
values = data.ExcelValues
有关我如何能够完成此任务的建议,而无需一次设置变量数组中的每个值吗?
答案 0 :(得分:3)
我找到了一个基于已发布here的代码的解决方案。变量数组必须作为对象从VBA传递到C#(而不是对象[,])。然后可以使用反射将其转换为更方便的东西:
[Guid("xxx")]
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Vector
{
[ComVisible(false)]
public IList<double> Values { get; set; }
public object[,] GetExcelValues()
{
// own extension method
return Values.ConvertToExcelColumn();
}
public void SetExcelValues(object comArray)
{
IEnumerable<object> values = ConvertExcelCloumnToEnumerable(comArray);
Values = new List<double>(values.Select(Convert.ToDouble));
}
private static IEnumerable<object> ConvertExcelCloumnToEnumerable(object comObject)
{
Type comObjectType = comObject.GetType();
if (comObjectType != typeof(object[,]))
return new object[0];
int count = (int)comObjectType.InvokeMember("Length", BindingFlags.GetProperty, null, comObject, null);
var result = new List<object>(count);
var indexArgs = new object[2];
for (int i = 1; i <= count; i++)
{
indexArgs[0] = i;
indexArgs[1] = 1;
object valueAtIndex = comObjectType.InvokeMember("GetValue", BindingFlags.InvokeMethod, null, comObject, indexArgs);
result.Add(valueAtIndex);
}
return result;
}
}
另一种方式 - 从C#到VBA - 它可以作为对象[,]或双[,]传递得更舒服。
希望没有语法拼写错误:)。
答案 1 :(得分:0)
通过使用Set,你告诉VBA“values”是一个对象(在本例中是一个Range),但是当你将它赋给ExcelValues时你没有使用set。在阅读值时尝试删除Set。
With myRange
values = Range(.Offset(0, 0), .Offset(100, 0)).Value
End With