1

这是我想要实现的目标:

用户复制一个单元格(或一个范围),例如 A3,并且 - 当她点击按钮时 - 我需要以编程方式访问单元格的地址(以创建链接)。

以文本格式访问剪贴板很容易:

string clip;

if (Clipboard.ContainsText()) clip = Clipboard.GetText();

我还发现可以访问不同格式的剪贴板,像这样

var dataObj = Clipboard.GetDataObject();
var format = DataFormats.CommaSeparatedValue;

if (dataObj != null && dataObj.GetDataPresent(format))
{
    var csvData = dataObj.GetData(format);
    //...
}

但我一辈子都找不到包含链接的格式以及如何获取它。(我循环浏览了 Clipboard.GetDataObject().GetFormats() 提供的所有格式,但有些返回了我无法理解的难以理解的流。

背景资料:

A. 链接必须在那里,因为我可以使用创建绝对引用的“粘贴链接”

B. 我在 Win7 下使用 Excel 2010 和 VS2010 - C#

C. 代码在自定义任务窗格中运行

任何帮助表示赞赏!


所以,

并感谢所有设法阅读到这一点的人。我终于弄明白了。我的解决方案仍然很尴尬,因为我无法从剪贴板了解流的实际结构,但我找到了我正在寻找的东西:

        protected override void WndProc(ref Message m)
        {
            const int WM_PASTE = 0x0302;
            var enc = new System.Text.UTF7Encoding();
            string buffer, rangeAddress;

            if (m.Msg == WM_PASTE)
            {
                if (Clipboard.ContainsText())
                {
                    string clip = Clipboard.GetText();
                    var dataObject = Clipboard.GetDataObject();
                    var mstream = (MemoryStream)dataObject.GetData("Link Source", true);
                    if(mstream == null) return;
                    var rdr = new System.IO.StreamReader(mstream, enc, true);
                    buffer = rdr.ReadToEnd();
                    buffer = StripWeirdChars(buffer);
                    int IndexExcl = buffer.IndexOf("!");
                    if (IndexExcl >= 0)
                    {
                        rangeAddress = buffer.Substring(IndexExcl + 1, buffer.Length - IndexExcl - 4);
                        // do whatever you want to do with it, e.g.:Globals.ThisAddIn.Application.ActiveCell.Value = rangeAddress;
                        return;
                    }
                }
            }
            base.WndProc(ref m);
        }
    }

这里的关键显然是 GetData 的特定格式:“链接源”。

读取结果流会生成一个包含许多奇怪字符的字符串,还有工作表的名称和复制范围的坐标。我用简单的方法去除了奇怪的字符

        public static string StripWeirdChars(string source)
        {
            string res = "";
            foreach (char c in source) if ((int)c >= 32) res += c;
            return res;
        }

仍然有一些奇怪的字符我无法理解,但好消息是,在第一个感叹号之后,您会找到范围的地址(带有一些固定长度的尾随垃圾)。即使该范围是从另一个工作表复制的,即使该工作表的名称中有奇数字符(如德语变音符号),这也有效。

肯定有一个更整洁的解决方案

通过IStream接口从剪贴板中获取Excel Range对象

但是我发现那里的代码不完整(“明显”的部分被遗漏了),由于我的无能和缺少 IStream 的经验,我无法让它工作。

感谢您使用它来获得一个简洁的解决方案的任何帮助,但我对我目前所拥有的感到满意。多谢你们。

4

2 回答 2

0

这只是来自@drdhk 的答案,因为在其中一条评论中要求这样做以表明已回答:

所以,

并感谢所有设法阅读到这一点的人。我终于弄明白了。我的解决方案仍然很尴尬,因为我无法从剪贴板了解流的实际结构,但我找到了我正在寻找的东西:

    protected override void WndProc(ref Message m)
    {
        const int WM_PASTE = 0x0302;
        var enc = new System.Text.UTF7Encoding();
        string buffer, rangeAddress;

        if (m.Msg == WM_PASTE)
        {
            if (Clipboard.ContainsText())
            {
                string clip = Clipboard.GetText();
                var dataObject = Clipboard.GetDataObject();
                var mstream = (MemoryStream)dataObject.GetData("Link Source", true);
                if(mstream == null) return;
                var rdr = new System.IO.StreamReader(mstream, enc, true);
                buffer = rdr.ReadToEnd();
                buffer = StripWeirdChars(buffer);
                int IndexExcl = buffer.IndexOf("!");
                if (IndexExcl >= 0)
                {
                    rangeAddress = buffer.Substring(IndexExcl + 1, buffer.Length - IndexExcl - 4);
                    // do whatever you want to do with it, e.g.:Globals.ThisAddIn.Application.ActiveCell.Value = rangeAddress;
                    return;
                }
            }
        }
        base.WndProc(ref m);
    }
}

这里的关键显然是 GetData 的特定格式:“链接源”。

读取结果流会生成一个包含许多奇怪字符的字符串,还有工作表的名称和复制范围的坐标。我用简单的方法去除了奇怪的字符

    public static string StripWeirdChars(string source)
    {
        string res = "";
        foreach (char c in source) if ((int)c >= 32) res += c;
        return res;
    }

仍然有一些奇怪的字符我无法理解,但好消息是,在第一个感叹号之后,您会找到范围的地址(带有一些固定长度的尾随垃圾)。即使该范围是从另一个工作表复制的,即使该工作表的名称中有奇数字符(如德语变音符号),这也有效。

肯定有一个更整洁的解决方案

通过 IStream 接口从剪贴板获取 Excel Range 对象:( http://www.codeproject.com/Articles/149009/Getting-the-Excel-Range-object-from-the-Clipboard )

但是我发现那里的代码不完整(“明显”的部分被忽略了),由于我的无能和缺少 IStream 的经验,我无法让它工作。

感谢您使用它来获得一个简洁的解决方案的任何帮助,但我对我目前所拥有的感到满意。多谢你们。

于 2015-10-14T14:39:58.440 回答
0

您的方法有一个限制:结果始终是矩形范围。如果您已将A1:B2A4:B5复制到剪贴板中,则您的方法将返回A1:B5,这意味着第3行包含在结果范围中,实际上,它不是范围的一部分剪贴板。有更多剪贴板数据类型包含较少奇怪的字符,例如ObjectLinkLink,但它们对非矩形范围具有相同的限制。

在选择范围的同时按 Ctrl 可以选择非矩形范围。

于 2016-06-11T11:43:59.773 回答