C# 剪貼簿測試
MSN Space、Google Doc 、Google Blog
Chui-Wen Chiu(Arick)
2007.02.27 備註兩點錯誤修正
2007.02.26 建立
.NET 中的剪貼簿由 Clipboard, DataFormats 和 IDataObject 所構成。這些類別定義在 System.Windows.Forms 名稱空間。
如果要檢測剪貼簿目前的資料型態可以透過 IDataObject.GetDataPresent 來檢測,如下
IDataObject d = Clipboard.GetDataObject();
Type t = typeof(DataFormats);
FieldInfo[] fis = t.GetFields();
foreach (FieldInfo fi in fis) {
Debug.Write(String.Format("{0} => ", fi.Name));
Debug.WriteLine(d.GetDataPresent(fi.Name) ? "YES" : "NO");
}
執行結果:
Text => YES
UnicodeText => YES
Dib => NO
Bitmap => NO
EnhancedMetafile => NO
MetafilePict => NO
SymbolicLink => NO
Dif => NO
Tiff => NO
OemText => YES
Palette => NO
PenData => NO
Riff => NO
WaveAudio => NO
FileDrop => NO
Locale => YES
Html => NO
Rtf => NO
CommaSeparatedValue => NO
StringFormat => NO
Serializable => NO
.NET2.0 對 Clipboard 新增 ContainsData,可以不用透過 IDataObject 來檢測料型態,修改如下:
Type t = typeof(DataFormats);
FieldInfo[] fis = t.GetFields();
foreach (FieldInfo fi in fis) {
Debug.Write(String.Format("{0} => ", fi.Name));
Debug.WriteLine(Clipboard.ContainsData(fi.Name) ? "YES" : "NO");
}
取得剪貼簿內容
IDataObject d = Clipboard.GetDataObject();
if (d.GetDataPresent(DataFormats.Text)) {
MessageBox.Show((String)d.GetData(DataFormats.Text));
}
if (d.GetDataPresent(DataFormats.Bitmap)) {
Bitmap b = (Bitmap)d.GetData(DataFormats.Bitmap);
this.BackgroundImage = b;
}
或是直接取用 .NET 2.0 新增的 Clipboard.GetData,如下:
Object obj;
if ( (obj = Clipboard.GetData(DataFormats.Text)) != null ){
MessageBox.Show((String)obj);
}
if ((obj = Clipboard.GetData(DataFormats.Bitmap)) != null) {
Bitmap b = (Bitmap)obj;
this.BackgroundImage = b;
}
將資料放置在剪貼簿內容
* 文字
Clipboard.SetData(DataFormats.Text, "Chui-Wen Chiu TEST!!");
* Bitmap
Clipboard.SetData(DataFormats.Bitmap, new Bitmap(@"c:snapshot20070213131306.bmp"));
備註:
1. 雖然 [1] 的範例在 Console 模式下展示,可是我實際在 .NET 2.0 的 Console 下使用 Clipboard.GetDataObject(),回傳值永遠為 null。 使用 Clipboard.ContainData 也無法正常檢測出資料型別。
依據[4]如下描述
"Clipboard 類別只能用在設定為單一執行緒 Apartment (STA) 模式的執行緒中。若要使用這個類別,請確定您的 Main 方法是STAThreadAttribute 屬性做為標記。"
所以,如果要在 Console 下使用剪貼簿必須使用 STAThreadAttribute,如下
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Reflection;
namespace ConsoleApplication1 {
class Program {
[STAThread]
static void Main(string[] args) {
IDataObject d = Clipboard.GetDataObject();
Type t = typeof(DataFormats);
FieldInfo[] fis = t.GetFields();
foreach (FieldInfo fi in fis) {
Debug.Write(String.Format("{0} => ", fi.Name));
Debug.WriteLine(d.GetDataPresent(fi.Name) ? "YES" : "NO");
}
}
}
}
2. 雖然 Clipboard.SetData 和 Clipboard.GetData 的資料格式都以 String 來識別,可是卻無法以自訂資料型態來擴充,如下:
Clipboard.SetData("MyData", new MyData("Chui-Wen Chiu", 1));
Object obj;
if ( (obj = Clipboard.GetData("MyData")) != null ){
MessageBox.Show(((MyData)obj).ToString());
}
public class MyData {
public String Name;
public int Sex;
public MyData(String name, int sex) {
Name = name;
Sex = sex;
}
public override string ToString() {
return String.Format("{0}={1}", Name, Sex);
}
}
2007.02.27 Update
依據 MSDN 描述[4],
"物件必須可以序列化,才能放在剪貼簿上。如果您將不可序列化的物件傳遞至 Clipboard 方法,則該方法會失敗而不擲回例外狀況。"
依據上述說明,將程式修正如下即可放置在剪貼簿中。
Clipboard.SetDataObject(new MyData("Chui-Wen Chiu", 1), false);
MyData m2=(MyData)Clipboard.GetData(typeof(MyData).ToString() );
MessageBox.Show(m2.ToString());
[Serializable]
public class MyData {
public String Name;
public int Sex;
public MyData(String name, int sex) {
Name = name;
Sex = sex;
}
public override string ToString() {
return String.Format("{0}={1}", Name, Sex);
}
}
另外,[3]描述剪貼簿可以放入任何物件,但為了避免傳遞給 SetDataObject 的物件不是字串、Metafile 或 Bitmap,必須在 SetDataObject 的第二個參數傳入 false,或是直接忽略第二個參數。這個限制是因為剪貼簿不能在應用程式之間傳遞任意物件,只有將自訂物件放入剪貼簿的應用程式可以存取他。
參考資料:
[1] Using the clipboard to transfer data to and from your applications
[2] Clipboard.GetDataObject 方法(System.Windows.Forms)
[3] Charles Petzold, "Microsoft Windows Programming With C#"
[4] Clipboard 類別(System.Windows.Forms)