標籤:對象 attribute rgs 定義 class line from 需要 main函數
剪下板是Windows系統提供的功能,從我最早接觸到的Windows 3.2版本開始,就一直帶著了。以前使用C++的時候,是直接使用Windows API對其進行操作的,到了.NET下,在WinForm中也有一個對剪下板的封裝類,即System.Windows.Forms.Clipboard,這個類其實是通過COM組件間接地使用剪下板的,我個人覺得COM是一個設計非常糟糕的東西,難懂坑多還不可移植,但微軟現存的大量代碼又是基於COM的,所以又無法徹底捨棄,關於不可移植這個並不難理解,前面說了,剪下板是Windows提供的功能,你在Linux下,或者在MacOS下,儘管有類似的功能,但跟Windows的肯定不同,所以最新的.NET Core中是不能使用剪下板功能的。
往剪下板裡存取字串
字串是最最常用的資料對象了,我們就往剪下板裡寫一個字串吧,我總結了一下,見下表:
| 方法1 |
Clipboard.SetText(str); |
很可能有問題 |
| 方法2 |
Clipboard.SetData(DataFormats.Text,str); |
很可能有問題 |
| 方法3 |
Clipboard.SetDataObject(str); |
大多數時候沒問題 |
嗯?怎麼這麼不確定?確實如此,這是我進行了大量實驗的結果,且程式在調試和非調試中還有不同的表現,可能出現的異常有以下兩個:
(異常1:COMException)
(異常2:ExternalException)
兩個異常都沒有進一步的提示資訊,異常的原因很類似,就是剪下板訪問不了,而我使用方法3的時候,在非調試狀態下還沒發現過什麼問題。我實在找不到進一步的規律了,先這樣用吧。
那麼如何從剪下板擷取字串呢?對應的,有兩種方法:
| 方法1 |
string str = (string)Clipboard.GetData(DataFormats.Text) |
很可能有問題 |
| 方法2 |
string str = Clipboard.GetText(); |
大多數時候沒問題 |
具體原因我同樣不太清楚,這似乎是微軟留下的一個bug,SO上有個討論,可以去看看:StackOverflow
另外還有兩點需要注意:
- 方法3這種往剪下板裡寫常值內容的方式,在這個程式結束之後,剪下板內容將會失效,要使得程式結束後剪下板內容繼續有效話,得使用Clipboard.SetDataObject(str, true);這個方法,第二個參數true表示讓剪下板內容在程式結束後繼續有效,但我發現加上這個參數之後,增加了出現異常的可能性。
- 必須在給程式的入口函數(通常是Main函數)加上STAThreadAttribute這個註解,否則對剪下板的訪問會報錯:在可以調用 OLE 之前,必須將當前線程設定為單一執行緒 Apartment(STA)模式。
往剪下板裡存取自訂資料
C#的對象的資料結構並不能為剪下板所理解,所以你要把你自訂的資料放到剪下板去的話要把它序列化,在實際操作中,是要你提供一個“可序列化”的對象,下面是個簡單的例子:
[Serializable]public class User { public int age { get; set; } public string name { get; set; }}class Program { [STAThread] static void Main(string[] args) { User userIn = new User(); userIn.name = "Jack"; userIn.age = 18; Clipboard.SetData("mydata", userIn); User userOut = (User)Clipboard.GetData("mydata"); Console.WriteLine(userOut.name +" | " + userOut.age); }}
注意User這個類前面的Serializable註解,如果沒有這個註解,是沒法成功將對象寫入剪下板的。如果資料比較複雜,可以考慮把資料自行序列化到一個Stream對象去,再把Stream對象寫入剪下板,擷取的時候對Stream對象自行還原序列化,還原資料。例子就不寫了。
最後要注意的一點是由於這裡的資料類型是“mydata”,你也可以指定別的名字,這種類型資料只有你自己的程式能讀懂,也就是說,你是不能開啟記事本或者Photoshop,直接把你這個User對象貼上去的。
C#操作剪下板(Clipboard)