使用 .NET 处理剪贴板 - 第二部分






4.71/5 (11投票s)
2002 年 6 月 4 日
5分钟阅读

205161

2600
基于第一部分,展示如何使用自定义/多种格式
引言
2002 年 4 月底,我和 Nish 正在尝试弄清楚 .NET 的一些剪贴板功能。谈话结束后,我们决定写一篇分为两部分的文章,Nish 负责 第一部分,介绍基础知识,然后我写第二部分,介绍一些更高级的主题。我打算在屏幕保护程序竞赛结束后尽快写完,不用说,我给忘了……直到现在。
在本文中,我希望涵盖多种数据格式,以及创建您自己的自定义数据格式。
多种数据格式
将多种数据格式放入剪贴板非常简单;一旦你知道窍门 :-)
第一个窍门……呃,第一步是弄清楚您将使用哪些数据格式。稍后我将讨论自定义格式,所以暂时忽略它们。为了帮助您查找,DataFormats
类包含一个以静态字符串字段形式存储的常用格式列表;有关那里列出的每种格式的详细信息,请参阅 MSDN。
现在您已经知道了要使用的格式,创建一个实现了 IDataObject
的类的实例,唯一这样的类是(恰如其分地)命名为 DataObject
。
IDataObject ido = new DataObject();
有了 IDataObject
接口,我们就可以开始使用它了。IDataObject
的目的是“[提供]一种与格式无关的数据传输机制”(MSDN,IDataObject
接口)。熟悉 COM 的人会对此对象非常熟悉。它可以存储您传入的每种格式的一个对象。因此,如果您需要存储 3 个 Text 格式的对象,您需要将它们包装成自定义格式,我稍后会解释。
ido.SetData(DataFormats.Text, true, myString);
那行代码将一个具有 myString 值的、新的 Text 格式的对象添加到 DataObject
,并允许它转换为其他类型。这将是您在 Win32 中使用 Clipboard
时发现的关键点。数据通常以多种格式存储,以便在各种程序中使用。通常,数据会以自定义格式、文本格式以及可能的位图(如果代表图形内容)的形式存储。这允许粘贴到许多应用程序中,并以本机格式粘贴到其自身中。
添加多种、额外的格式就像使用不同的格式调用 SetData
一样简单。
Clipboard.SetDataObject(ido, true);
这一行最终将数据放置在剪贴板上,任何程序都可以读取。true
参数告诉 Clipboard
即使程序退出后也要使数据可用。稍后我将介绍第二个参数的另一个重要注意事项,MSDN 未提及。
将数据复制到 Clipboard
后,您就可以像之前一样粘贴它了;检查正确的数据格式,然后如果存在则检索它。
IDataObject ido = Clipboard.GetDataObject();
if(ido.GetDataPresent(DataFormats.Text))
{
// Text data is present on the clipboard
textBox1.Text = (string) ido.GetData(DataFormats.Text);
}
自定义数据格式
自定义数据格式可以是任何东西;无论是特殊的文本格式(如 HTML 或 XML),还是类实例。要使用自定义格式,首先需要向 Windows 注册它。在演示应用程序中,您会发现我在自定义类型类 CustomData 的静态构造函数中向 Windows 注册了该类型。
static CustomData
{
format = DataFormats.GetFormat(
typeof(CustomData).FullName
);
}
代码 typeof(CustomData).FullName
仅检索类型的完整名称;因为我需要选择一个唯一的名称,所以我认为这就可以了。GetFormat
返回 DataFormats.Format
类的一个实例,我将其存储为静态属性,以便访问格式的 Name
和 ID
。名称不一定相关,只要唯一即可,Windows 注册了一个 Format17,用于屏幕截图。
使用类创建自定义格式的唯一独特之处在于,该类必须是可序列化的,即需要应用 Serializable
属性。
[Serializable()]
public class CustomData
.....
要在剪贴板上使用它,就像使用任何其他格式一样。
IDataObject ido = new DataObject();
CustomData cd = new CustomData(myImage, myString);
ido.SetData(CustomData.Format.Name, false, cd);
从其中检索数据与之前相同。
IDataObject ido = Clipboard.GetDataObject();
if( ido.GetDataPresent(CustomData.Format.Name) )
{
// Do something interesting with the data
CustomData cd = (CustomData)
ido.GetData(CustomData.Format.Name);
}
持久化剪贴板上的数据,即 SetDataObject 的第二个参数
根据 MSDN,第二个参数告诉 Clipboard
对象,当应用程序退出时,内部数据是否应该持久化。但这并非全部。它实际上是在数据真正需要时才延迟数据的序列化。
为了在实践中看到这一点,请运行包含的 ClipboardTest2 应用程序,取消选中“Persist Data”(持久化数据);然后继续进行 Draw、Copy 和 Paste,然后进行 Draw 和 Paste。您会看到,即使数据只复制了一次,也会显示新数据。
原因在于我继续操作传递到 IDataObject
的 SetData
方法的同一个对象,因为我们告诉 Clipboard 对象在需要时才序列化数据,它就是这么做的。最重要的是,每次请求数据时,它都会重新序列化数据。奇怪的是,它只更新指定的格式,一旦格式的初始序列化发生,所有自动转换的格式都不会受到影响。
为了演示这一点,请再次打开 ClipboardTest2 应用程序,取消选中“Persist Data”(持久化数据);然后进行 Draw、Copy 和 Paste。继续进行 Draw 和 Paste,然后打开您喜欢的图像编辑软件;MSpaint 也可以。现在将其粘贴到 MSpaint 中;再进行一些 Draw 和 Pastes,然后在另一个 MSpaint 副本中再次粘贴。您会看到相同的位图被粘贴到了两个 MSpaint 中。
这似乎是一个错误,但实际上是我使用上的一个错误。一旦您将一个对象放入剪贴板,预期的结果是该对象保持不变;而不是像我那样改变它。这意味着最佳解决方案是创建一个副本并将其缓存到某处,直到 Clipboard 对象需要它为止。
如果您选择不将数据持久化到剪贴板,在应用程序退出时,您应该将数据重新放到剪贴板上并持久化它;以便内容仍然可供用户使用。
结论
好了,各位,这就是剪贴板的全部光辉。希望我没有太让您感到厌烦。一如既往,请在下方留下问题或评论;如果您发现任何错误,请通过电子邮件发送给我。
对于那些对屏幕截图中的视觉样式感兴趣的人,我从 themexp.org 获取的;您还需要 StyleXP 或同一网站提供的 uxtheme.dll 的免费更新。