在 .NET Excel 插件中设置剪贴板中的自定义数据
我有一个用 C# 编写的 Excel 插件,其中有一些复制/粘贴处理代码。当用户复制时,我想将自己的 TableData 类对象放在剪贴板上,并在用户将数据粘贴到工作表上时检索它。听起来很简单,我在网上找到了十几篇文章,但由于某种原因它在我的代码中不起作用。
这是我的 TableData 类:
[Serializable]
[Guid("794E06D9-7CE4-40dc-8187-BDC105A0F866")]
public class TableData
{
public string Name;
public TableData()
{ }
}
我什至给了它一个 GUID,以确保它加载完全相同的类,即使它是从其他程序集加载的(如果加载项对象由于某种原因加载了两次)。
这就是我在复制时设置数据的方法:
TableData data = new TableData();
data.Name = "test";
Clipboard.SetData("MyTable", data);
在粘贴时:
TableData data = Clipboard.GetData("MyTable") as TableData;
此处>>数据为空,但如果我在立即窗口中打印 GetData("MyTable"),它会显示 即使使用 BinaryFormatter::DeSerialize() 方法我也无法将内存流转换为 TableData
我可能在这里犯了一些愚蠢的错误,但我无法弄清楚。有人可以指出这里的问题吗?
更新
它是一个 COM 插件,而不是 VSTO 插件。我已在 OnKey 方法中设置宏,以便当用户在 Excel 工作表中按 CTRL+C 和 CTRL+V 时调用它们。有一个单独的 VBA 模块可以处理这些请求并将它们路由到 .NET 插件。
Application.OnKey("^c", "OnCopy");
因此,调用转到 VBA,然后 VBA 回调到我的 .NET 插件。不确定调用之间是否涉及其他进程。
如果我从剪贴板中放置和检索 byte[],但不适用于我的自定义类,则工作正常
I have a Excel addin written in C# that has some Copy/Paste processing code. When the user copies, I want to put my own TableData class object on the clipboard and retrieve it back when the user paste the data on the worksheet. Sounds real simple and I found a dozen articles online but for some reason it is not working in my code.
Here is my TableData class:
[Serializable]
[Guid("794E06D9-7CE4-40dc-8187-BDC105A0F866")]
public class TableData
{
public string Name;
public TableData()
{ }
}
I even gave it a GUID to make sure its loading the exact same class even if it is loading from some other assembly (if addin object loaded twice for some reason).
This is what I am doing to set data while copying:
TableData data = new TableData();
data.Name = "test";
Clipboard.SetData("MyTable", data);
And on Paste:
TableData data = Clipboard.GetData("MyTable") as TableData;
HERE >> data is null but if I print the GetData("MyTable") in immediate window, it shows
a memory stream which I was unable to convert to TableData even by using the BinaryFormatter::DeSerialize() method
I might be doing some silly mistake here but I am unable to figure it out. Can somebody point out the problem here?
UPDATED
It is a COM addin and NOT a VSTO addin. I have set the macros in OnKey method so they get called when the user presses CTRL+C and CTRL+V in Excel worksheet. There is a separate VBA module that handles these requests and routes them to the .NET addin.
Application.OnKey("^c", "OnCopy");
So the call goes to VBA and then the VBA calls back into my .NET addin. Not sure if there is some other process involved in between the calls.
Works fine if I put and retrieve byte[] from the clipboard but not for my custom class
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
明白了!
问题是代码在粘贴期间无法找到相同类型。这是因为插件所在的位置与主机应用程序(即 Excel)不同。
我尝试序列化该类,然后将其放在剪贴板上。然后将其反序列化回原始类型,但在反序列化过程中失败,并抛出“TargetInitationException* 并提示“无法找到程序集[插件程序集全名]”。Clipboard::SetData( ...) 没有抛出任何异常,它只是默默地处理它并返回 NULL。
解决方案是处理 AppDomain.CurrentDomain.AssemblyResolve 事件并在查询插件时返回当前正在执行的程序集 。集结来了。
Gotcha!!
The problem was that the code was unable to find the same type during Paste. This is because that the addin was at location different from the host application i.e. Excel.
I tried by serializing the class and then putting it on the clipboard. Then De-Serializing it back to the original type but it failed during De-Serialize and a "TargetInvocationException* was thrown saying "Unable to find assembly [addin assembly full name]". Clipboard::SetData(...) was not throwing any exception, it was just silently handling it and returning NULL.
The solution is to handle the AppDomain.CurrentDomain.AssemblyResolve event and return the current executing assembly when a query for addin's assembly comes.
我创建了一个简单的 VSTO 插件,其中包含复制和粘贴按钮以及上面的确切代码。
Table 对象在粘贴处理程序中正确可用。
I created a simple VSTO addin with a Copy and a Paste button with the exact code above.
The Table object is correctly available in the Paste hander.
这篇文章列出了一些可能有帮助的步骤。其中包括注册剪贴板格式,显式创建 DataObject 并将其数据设置为 TableData,然后将剪贴板数据设置为 DataObject。值得一试,因为它只有几行代码。
This article lists some steps that may help. These include registering the clipboard format, and explicitly creating a DataObject and setting its data to your TableData, and then setting the clipboard data to the DataObject. It's worth a shot since it is only a few lines of code.