Работа с Windows Clipboard в C#

Прочитав эту статью, вы узнаете некоторые приемы работы с буфером обмена на примере C# .NET. Мы посмотрим, каким требованиям должен отвечать класс, чтобы он мог быть сохранен в буфер обмена. В Интернете я нашел на удивление мало информации по данному вопросу. На форумах мне попадалось на глаза множество сообщений типа "помогите, при попытке получения информации из буфера обмена всегда возвращается null". Большинство ответов были отрицательными, некоторые же из них примерно следующего характера: "вы не можете сохранить тип, передаваемый по ссылке, в буфер обмена". В связи с этим я решил поделиться с вами некоторыми своими наработками.
Сериализация
Сериализация представляет собой процесс сохранения объекта в такой форме, в которой он может быть легко передан, скопирован на жесткий диск, отослан по электронной почте и т.п. И наоборот: десериализация есть не что иное, как создание экземпляра объекта из этого представления (например, из потока байтов). Первое и единственное требование при работе с буфером обмена — ваш класс должен быть сериализуемым. Для достижения поставленной цели у нас, как обычно, есть два пути. Первый из них — реализовать интерфейс ISerializable. Второй, и наиболее простой — пометить класс атрибутом Serializable:
[Serializable]
public class Document
{
public int documentID = 0;
public string documentDescription = "";
}
Заметьте, что, если ваш класс унаследован от другого базового класса, то этот базовый класс также должен быть помечен атрибутом Serializable:
[Serializable]
public class Document
{
public int documentID = 0;
public string documentDescription = "";
}
[Serializable]
public class EmailDocument: Document
{
public string subject = "";
public string body = "";
}
Обратите внимание и на тот факт, что, если ваш код содержит закрытые поля, которые не могут быть сериализованы (или вы не хотите, чтобы они были сериализованы), вы должны пометить их атрибутом NonSerialized:
[Serializable]
public class Document
{
public int documentID = 0;
public string documentDescription = "";
[NonSerialized]
private System.Data.SqlClient.SqlCommand cmd;
[NonSerialized]
private System.Data.SqlClient.SqlConnection cn;
}
Возможна ли сериализация?
Чтобы определить, возможно ли сохранение объекта в буфер обмена, добавим к нашему классу Document простой метод IsSerializable(object obj). Он использует класс BinaryFormatter для сериализации объекта в MemoryStream. Этот метод увеличивает расход памяти, поэтому используйте его только на этапе отладки. Удалите данный метод из приложения по окончании тестирования.
using System.Runtime.Serialization.Formatters.Binary;
private static bool IsSerializable(object obj)
{
System.IO.MemoryStream mem = new System.IO.MemoryStream();
BinaryFormatter bin = new BinaryFormatter();
try {
bin.Serialize(mem, obj);
return true;
} catch(Exception ex) {
MessageBox.Show("Объект не может быть сериализован. \n" + ex.ToString());
return false;
}
}
Форматы, поддерживаемые буфером обмена
Каждое приложение сохраняет данные в буфер обмена в каком-либо формате (либо в нескольких форматах). Существуют стандартные форматы — такие, как Text, Image, Wave Audio, HTML text и пр. Эти типы регистрируются в Windows уже на этапе установки. Любое приложение "знает", какие форматы оно поддерживает, таким образом, этому приложению известно, возможно ли вставить в него данные, содержащиеся в буфере обмена. Приложение может сохранять данные, используя один из стандартных форматов, или зарегистрировать свой собственный.
Класс Clipboard
Доступ к буферу обмена и сохранение в нем данных из Windows-приложения позволяет осуществить метод SetDataObject() класса Clipboard, который сохраняет информацию в буфер, используя интерфейс IDataObject. Через этот интерфейс происходит и восстановление данных из буфера.
Копирование в буфер обмена
Чтобы сохранить свой объект в буфер обмена, вам необходимо зарегистрировать свой собственный формат (если он еще не зарегистрирован), создать экземпляр DataObject, заполненный данными, и передать его на вход метода ClipBoard.SetDataObject(). Все, что вам нужно для регистрации своего собственного формата данных, — придумать ему название! А затем вызвать статический член DataFormats.GetFormat(). Лично мне кажется, что наиболее оптимальным именем для нового формата является полное имя его типа. Как видно из нижеследующего листинга, я добавил метод CopyToClipboard() к нашему классу Document.
public void CopyToClipboard()
{
// регистрируем свой собственный формат данных либо получаем его, если он уже зарегистрирован
DataFormats.Format format = DataFormats.GetFormat(typeof(Document).FullName);
// копируем в буфер обмена
IDataObject dataObj = new DataObject();
dataObj.SetData(format.Name, false, this);
Clipboard.SetDataObject(dataObj, false);
}
Получение данных из буфера обмена
Перед тем, как получать какие-либо данные из буфера обмена, нужно убедиться, что формат данных в буфере совместим с вашим приложением. Сперва вызываем метод GetDataPresent() экземпляра класса DataObject. А уже после этого — метод GetData() интерфейса IDataObject. Следующий код демонстрирует, как получить объект Document из буфера:
protected static Document GetFromClipboard()
{
Document doc = null;
IDataObject dataObj = Clipboard.GetDataObject();
string format = typeof(Document).FullName;
if(dataObj.GetDataPresent(format)) {
doc = dataObj.GetData(format) as Document;
}
return doc;
}

Вольный перевод Алексея Нестерова
Оригинальную версию статьи можно найти по адресу:
http://www.codeproject.com/csharp/CopyCustomClassToClipbrd.asp

Александр Юмашев


Компьютерная газета. Статья была опубликована в номере 37 за 2004 год в рубрике программирование :: разное

©1997-2024 Компьютерная газета