Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
ПРОГРАММИРОВАНИЕ НА C и С++
Работа с буфером обмена.
Реализация команд Cut, Copy, и Paste
В этом разделе приводится пример, реализующий эти команды используя два формата буфера обмена: CF_OWNERDISPLAY и CF_TEXT. Обычно, перед тем, как информация будет скопирована в буфер обмена (clipboard), пользователь должен выделить определённый кусок текста. Для этого в приложении должны быть реализованы все возможности. После того, как текст будет выделен, необходимо реализовать всплывающее меню по правой кнопке мыши, а так же акселераторы к пунктам этого меню.
Чтобы сделать всплывающее меню, приложение должно обработать сообщение WM_INITMENUPOPUP:
case WM_INITMENUPOPUP:
InitMenu((HMENU) wParam);
break;
Функция InitMenu позволяет сделать определённые пункты меню доступными либо недоступными (серыми) и выглядит следующим образом:
Пример:
void WINAPI InitMenu(HMENU hmenu)
{
int cMenuItems = GetMenuItemCount(hmenu);
int nPos;
UINT id;
UINT fuFlags;
PLABELBOX pbox = (hwndSelected == NULL) ? NULL :
(PLABELBOX) GetWindowLong(hwndSelected, 0);
for (nPos = 0; nPos < cMenuItems; nPos++)
{
id = GetMenuItemID(hmenu, nPos);
switch (id)
{
case IDM_CUT:
case IDM_COPY:
case IDM_DELETE:
if (pbox == NULL || !pbox->fSelected)
fuFlags = MF_BYCOMMAND | MF_GRAYED;
else if (pbox->fEdit)
fuFlags = (id != IDM_DELETE && pbox->ichSel
== pbox->ichCaret) ?
MF_BYCOMMAND | MF_GRAYED :
MF_BYCOMMAND | MF_ENABLED;
else
fuFlags = MF_BYCOMMAND | MF_ENABLED;
EnableMenuItem(hmenu, id, fuFlags);
break;
case IDM_PASTE:
if (pbox != NULL && pbox->fEdit)
EnableMenuItem(hmenu, id,
IsClipboardFormatAvailable(CF_TEXT) ?
MF_BYCOMMAND | MF_ENABLED :
MF_BYCOMMAND | MF_GRAYED
);
else
EnableMenuItem(hmenu, id,
IsClipboardFormatAvailable(
uLabelFormat) ?
MF_BYCOMMAND | MF_ENABLED :
MF_BYCOMMAND | MF_GRAYED
);
}
}
}
Далее, для того, чтобы обрабатывать команды меню, необходимо добавить в приложение обработку команды WM_COMMAND в главную оконную процедуру:
Пример:
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_CUT:
if (EditCopy())
EditDelete();
break;
case IDM_COPY:
EditCopy();
break;
case IDM_PASTE:
EditPaste();
break;
case IDM_DELETE:
EditDelete();
break;
case IDM_EXIT:
DestroyWindow(hwnd);
}
break;
Для реализации команд Copy и Cut используется функция EditCopy (См. Копирование данных в буфер обмена). Для реализации команды Paste используется функция EditPaste (См. Вставка данных из буфера обмена).
Копирование информации в буфер обмена
Процесс копирования информации в буфер обмена осуществляется следующим образом:
Открываем буфер обмена функцией OpenClipboard.
Очищаем буфер обмена функцией EmptyClipboard.
Вызываем функцию SetClipboardData для каждого формата буфера обмена, которые поддерживает приложение.
Закрываем буфер обмена функцией CloseClipboard.
Для того чтобы скопировать выделенный текст, используется следующая структура:
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX {
RECT rcText; // координаты прямоугольника с текстом
BOOL fSelected; // TRUE если выделен label
BOOL fEdit; // TRUE если текст выделен
int nType; // прямоугольное или овальное
int ichCaret; // позиция каретки
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // длина текста в atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
А вот сама функция EditCopy:
Пример:
BOOL WINAPI EditCopy(VOID)
{
PLABELBOX pbox;
LPTSTR lptstrCopy;
HGLOBAL hglbCopy;
int ich1, ich2, cch;
if (hwndSelected == NULL)
return FALSE;
// Открываем буфер обмена и очищаем его.
if (!OpenClipboard(hwndMain))
return FALSE;
EmptyClipboard();
// Получаем указатель на структуру LABELBOX.
pbox = (PLABELBOX) GetWindowLong(hwndSelected, 0);
// Если текст выделен, то копируем его используя формат CF_TEXT.
if (pbox->fEdit)
{
if (pbox->ichSel == pbox->ichCaret) // нулевая длина
{
CloseClipboard(); // выделение
return FALSE;
}
if (pbox->ichSel < pbox->ichCaret)
{
ich1 = pbox->ichSel;
ich2 = pbox->ichCaret;
}
else
{
ich1 = pbox->ichCaret;
ich2 = pbox->ichSel;
}
cch = ich2 - ich1;
// Выделяем память для текста.
hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglbCopy == NULL)
{
CloseClipboard();
return FALSE;
}
// Блокируем хэндл и копируем текст в буфер.
lptstrCopy = GlobalLock(hglbCopy);
memcpy(lptstrCopy, &pbox->atchLabel[ich1],
cch * sizeof(TCHAR));
lptstrCopy[cch] = (TCHAR) 0; // нулевой символ
GlobalUnlock(hglbCopy);
// Помещаем хэндл в буфер обмена.
SetClipboardData(CF_TEXT, hglbCopy);
}
// Если текст не выделен, то копируем весь label.
else
{
// Сохраняем копию выделенного лабела в локальной памяти.
// С ней мы будем работать и освобождать в ответ на
// сообщение WM_DESTROYCLIPBOARD.
pboxLocalClip = (PLABELBOX) LocalAlloc(
LMEM_FIXED,
sizeof(LABELBOX)
);
if (pboxLocalClip == NULL)
{
CloseClipboard();
return FALSE;
}
memcpy(pboxLocalClip, pbox, sizeof(LABELBOX));
pboxLocalClip->fSelected = FALSE;
pboxLocalClip->fEdit = FALSE;
// Помещаем в буфер обмена данные трёх форматов.
SetClipboardData(uLabelFormat, NULL);
SetClipboardData(CF_OWNERDISPLAY, NULL);
SetClipboardData(CF_TEXT, NULL);
}
// Закрываем буфер обмена.
CloseClipboard();
return TRUE;
}
Вставка данных из буфера обмена
Процесс вставки информации из буфера обмена осуществляется следующим образом:
Открываем буфер обмена функцией OpenClipboard.
Определяем форматы данных, хранящихся в буфере обмена.
Получаем хэндл данных нужного формата при помощи функции GetClipboardData.
Вставляем копию данных в документ.
Владельцем хэндла возвращённого GetClipboardData остаётся всё ещё буфер обмена, поэтому приложение не должно его освобождать.
Закрываем буфер обмена функцией CloseClipboard.
Определение структуры LABELBOX:
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX {
RECT rcText; // координаты прямоугольника с текстом
BOOL fSelected; // TRUE если будет копироваться весь label
BOOL fEdit; // TRUE если текст выделен
int nType; // прямоугольное или овальное
int ichCaret; // позиция каретки
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // длина текста в atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
Далее следует исходник функции EditPaste.
пример:
VOID WINAPI EditPaste(VOID)
{
PLABELBOX pbox;
HGLOBAL hglb;
LPTSTR lptstr;
PLABELBOX pboxCopy;
int cx, cy;
HWND hwnd;
pbox = hwndSelected == NULL ? NULL :
(PLABELBOX) GetWindowLong(hwndSelected, 0);
// Если приложение находится в режиме редактирования,
// то получаем текст из буфера обмена.
if (pbox != NULL && pbox->fEdit)
{
if (!IsClipboardFormatAvailable(CF_TEXT))
return;
if (!OpenClipboard(hwndMain))
return;
hglb = GetClipboardData(CF_TEXT);
if (hglb != NULL)
{
lptstr = GlobalLock(hglb);
if (lptstr != NULL)
{
// Функция ReplaceSelection вставляет текст
// и перерисовывает окно.
ReplaceSelection(hwndSelected, pbox, lptstr);
GlobalUnlock(hglb);
}
}
CloseClipboard();
return;
}
// Если приложение не находится в режиме редактирования,
// то создаём окно label-а.
if (!IsClipboardFormatAvailable(uLabelFormat))
return;
if (!OpenClipboard(hwndMain))
return;
hglb = GetClipboardData(uLabelFormat);
if (hglb != NULL)
{
pboxCopy = GlobalLock(hglb);
if (pboxCopy != NULL)
{
cx = pboxCopy->rcText.right + CX_MARGIN;
cy = pboxCopy->rcText.top * 2 + cyText;
hwnd = CreateWindowEx(
WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT,
atchClassChild, NULL, WS_CHILD, 0, 0, cx, cy,
hwndMain, NULL, hinst, NULL
);
if (hwnd != NULL)
{
pbox = (PLABELBOX) GetWindowLong(hwnd, 0);
memcpy(pbox, pboxCopy, sizeof(LABELBOX));
ShowWindow(hwnd, SW_SHOWNORMAL);
SetFocus(hwnd);
}
GlobalUnlock(hglb);
}
}
CloseClipboard();
}
Как зарегистрировать формат буфера обмена
Для этого используется функция RegisterClipboardFormat, которая обычно вызывается при инициализации приложения.
// atchTemp может содержать имя формата
// и завершаться нулевым символом.
//
LoadString(hinstCurrent, IDS_FORMATNAME, atchTemp,
sizeof(atchTemp)/sizeof(TCHAR));
uLabelFormat = RegisterClipboardFormat(atchTemp);
if (uLabelFormat == 0)
return FALSE;
Обработка сообщений WM_RENDERFORMAT и WM_RENDERALLFORMATS
Если не известно, какого формата данные будут помещены в буфер обмена, то можно передать в функцию SetClipboardData хэндл равный NULL, при этом приложение сгенерирует сообщениеWM_RENDERFORMAT либо WM_RENDERALLFORMATS и Вы должны позаботиться, чтобы обработать эти сообщения. В данном случае перед вызовом функции SetClipboardData нельзя открывать буфер обмена.
Сообщения WM_RENDERFORMAT и WM_RENDERALLFORMATS обрабатываются следующим образом:
case WM_RENDERFORMAT:
RenderFormat((UINT) wParam);
break;
case WM_RENDERALLFORMATS:
RenderFormat(uLabelFormat);
RenderFormat(CF_TEXT);
break;
Код функции RenderFormat представлен ниже.
Как обычно, определение структуры LABELBOX:
#define BOX_ELLIPSE 0
#define BOX_RECT 1
#define CCH_MAXLABEL 80
#define CX_MARGIN 12
typedef struct tagLABELBOX {
RECT rcText; // координаты прямоугольника с текстом
BOOL fSelected; // TRUE если будет копироваться весь label
BOOL fEdit; // TRUE если текст выделен
int nType; // прямоугольное или овальное
int ichCaret; // позиция каретки
int ichSel; // with ichCaret, delimits selection
int nXCaret; // window position corresponding to ichCaret
int nXSel; // window position corresponding to ichSel
int cchLabel; // длина текста в atchLabel
TCHAR atchLabel[CCH_MAXLABEL];
} LABELBOX, *PLABELBOX;
Пример:
void WINAPI RenderFormat(UINT uFormat)
{
HGLOBAL hglb;
PLABELBOX pbox;
LPTSTR lptstr;
int cch;
if (pboxLocalClip == NULL)
return;
if (uFormat == CF_TEXT)
{
// Выделяем буфер для текста.
cch = pboxLocalClip->cchLabel;
hglb = GlobalAlloc(GMEM_MOVEABLE,
(cch + 1) * sizeof(TCHAR));
if (hglb == NULL)
return;
// Копируем текст из pboxLocalClip.
lptstr = GlobalLock(hglb);
memcpy(lptstr, pboxLocalClip->atchLabel,
cch * sizeof(TCHAR));
lptstr[cch] = (TCHAR) 0;
GlobalUnlock(hglb);
// Помещаем хэндл в буфер обмена.
SetClipboardData(CF_TEXT, hglb);
}
else if (uFormat == uLabelFormat)
{
hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(LABELBOX));
if (hglb == NULL)
return;
pbox = GlobalLock(hglb);
memcpy(pbox, pboxLocalClip, sizeof(LABELBOX));
GlobalUnlock(hglb);
SetClipboardData(uLabelFormat, hglb);
}
}
Обработка сообщения WM_DESTROYCLIPBOARD
Чтобы освободить различные ресурсы, можно включить в приложение обработку сообщения WM_DESTROYCLIPBOARD. Например, при копировании label-а в буфер обмена, выделяется локальная память. Эту память можно освободить при обработке сообщения WM_DESTROYCLIPBOARD.
case WM_DESTROYCLIPBOARD:
if (pboxLocalClip != NULL)
{
LocalFree(pboxLocalClip);
pboxLocalClip = NULL;
}
break;
Использование формата буфера обмена CF_OWNERDISPLAY
Если Вы помещаете данные в буфер обмена, используя формат CF_OWNERDISPLAY, то необходимо проделать следующее:
Обработать сообщение WM_PAINTCLIPBOARD. Это сообщение посылается владельцу буфера обмена, когда его "окно" должно быть перерисовано.
Обработать сообщение WM_SIZECLIPBOARD. Это сообщение посылается владельцу буфера обмена, когда размеры его "окна" изменились либо изменилось его содержимое.
Обычно при этом, устанавливается положение скрола и диапазон скроллирования окна буфера обмена.
Обработать сообщения WM_HSCROLLCLIPBOARD и WM_VSCROLLCLIPBOARD. Эти сообщения посылаются владельцу буфера обмена, когда "окно" буфера обмена было проскроллировано.
Обработать сообщение WM_ASKCBFORMATNAME. Это сообщение посылает буфер обмена приложению, чтобы узнать формат.
Ниже представлена оконная процедура, с обработкой этих сообщений.
Пример:
LRESULT CALLBACK MainWindowProc(hwnd, msg, wParam, lParam)
HWND hwnd;
UINT msg;
WPARAM wParam;
LPARAM lParam;
{
static RECT rcViewer;
RECT rc;
LPRECT lprc;
LPPAINTSTRUCT lpps;
switch (msg)
{
//
// Обрабатываем другие сообщения.
//
case WM_PAINTCLIPBOARD:
// Определяем размер лабела.
SetRect(&rc, 0, 0,
pboxLocalClip->rcText.right + CX_MARGIN,
pboxLocalClip->rcText.top * 2 + cyText
);
// Центрируем картинку в окне буфера обмена.
if (rc.right < rcViewer.right)
{
rc.left = (rcViewer.right - rc.right) / 2;
rc.right += rc.left;
}
if (rc.bottom < rcViewer.bottom)
{
rc.top = (rcViewer.bottom - rc.bottom) / 2;
rc.bottom += rc.top;
}
// Рисуем изображение, используя структуру PAINTSTRUCT.
lpps = (LPPAINTSTRUCT) GlobalLock((HGLOBAL) lParam);
PaintLabel(lpps, pboxLocalClip, &rc);
GlobalUnlock((HGLOBAL) lParam);
break;
case WM_SIZECLIPBOARD:
// Записываем размеры окна в статической
// структуре RECT.
lprc = (LPRECT) GlobalLock((HGLOBAL) lParam);
memcpy(&rcViewer, lprc, sizeof(RECT));
GlobalUnlock((HGLOBAL) lParam);
// Устанавливаем диапазон скроллирования в ноль.
SetScrollRange((HWND) wParam, SB_HORZ, 0, 0, TRUE);
SetScrollRange((HWND) wParam, SB_VERT, 0, 0, TRUE);
break;
case WM_ASKCBFORMATNAME:
LoadString(hinst, IDS_OWNERDISPLAY,
(LPSTR) lParam, wParam);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
Прежде чем поместить в буфер обмена какую-либо информацию, ваша программа (далее просто окно) должна его открыть, используя функцию OpenClipboard. Однако следует учесть тот факт, что одновременно только одно окно может открыть буфер обмена. Следую хорошему тону программирования - если мы что-либо открыли, то нужно и закрыть. Работа с буфером обмена не является исключением для этого правила, следовательно, когда окно закончит работу, оно должно закрыть буфер обмена, вызвав функцию CloseClipboard.
После того как программа открыла буфер обмена, она должна его очистить от предыдущего содержания, для чего следует вызвать функцию EmptyClipboard. В обязанности этой функции входит посылка сообщения WM_DESTROYCLIPBOARD предыдущему владельцу буфера обмена, освобождение ресурсов, связанных с данными в буфере обмена. После этих операций данная функция передает в монопольное использование буфер обмена окну, которое вызвало функцию OpenClipboard.
После того как мы открыли буфер обмена и очистили его, мы имеем полное право помещать в него свои данные в различных форматах, используя функцию SetClipboardData (см. описание функции для описания стандартных форматов данных).
Чтобы извлечь информацию из буфера обмена, окно должно вызвать функцию GetClipboardData.
Данная функция в качестве параметра принимает формат буфера обмена, для того чтобы извлечь данные в этом формате. Если в буфер обмена данные поместила другая программа, вы можете проверить доступные форматы данных перед их непосредственным извлечением, используя функцию IsClipboardFormatAvailable.
Полученную теоретическую информацию следует применить на практике. Ниже приведены примеры работы с буфером обмена, в качестве форматов данных будет использован текст и изображение, поскольку работа с буфером обмена является типичной для любого формата данных, разница лишь в способе формирования исходных данных.
Пример записи и чтения текста.
CString source; |
Пример записи и чтения изображения (bitmap).
//запись изображения в буфер обмена |
Подводя итог этого раздела можно выделить следующие основные шаги для записи и чтения данных при работе с буфером обмена. Для того чтобы записать данные в буфер обмена, вы должны выполнить следующую последовательность действий:
Процедура чтения данных из буфера обмена тоже проста. Приложение должно сделать следующее:
#ifdef USE_MY_TRACE |
class MacroCall |
#ifdef USE_MACRO |
MYMACRO("%s : %d\r\n", "Value", 10); |
MYMACRO(55); |
MacroCall()(55); |
MacroCall().operator()(55); |
MYMACRO(55); // вызван operator()(int val) |
#define MYMACRO |
#define MYMACRO ((void)0) |
class MacroCallLine |
#define TRACEMSG MacroCallLine(__LINE__) |
TRACEMSG("My message"); |
#define MYMACRO MacroCall() |
#define MYMACRO(p) MacroCall(p) // ЭТО УЖЕ ДРУГОЙ ВЫЗОВ |
Когда мы наводим на какой-то файл или папку курсор, нажимаем правой кнопкой мыши и выбираем «Копировать» (или сочетание клавиш Ctrl+C), в этом момент информация помещается в буфер обмена.
Туда мы можем копировать все что угодно: текст, папку, картинки, видео-файлы, аудиозаписи и прочие файлы. Компьютер выделит нужное место в оперативной памяти для хранения в буфере нужного объема информации.
Можно представить что это оперативная память компьютера, или своеобразная невидимая область, куда помещается информация на время, а затем удаляется.
То есть, когда мы перейдем в нужное место на нашем компьютере и опять же нажмем правой кнопкой мыши, но выберем уже «Вставить» (или сочетание клавиш Ctrl+V), то та папка, или файл, или кусок текста, который вы скопировали, возьмется из буфера обмена и вставится в нужное вам место.
А это значит, что начинающему пользователь не стоит беспокоиться о том, где именно это информация храниться. Главное, что мы можем вставить ее в нужное нам место.
Следует также понимать, что когда вы опять нажимаете «Копировать», то старая информация в буфере заменяется на новую и при вставке, естественно, вставляется новая. Тоже самое происходит, если вы что-то «вырезаете».
Вы также можете вставлять информацию из буфера любое количество раз, т.е. при вставке информация от-туда не удаляется, она как-бы копируется.
И если вы скопировали папку, то вы можете вставить ее и на диск С, и на диск Е и в любое другое место на компьютере.
Также обратите внимание на то, что если вы скопировали в буфер обмена какой-то кусок текста из документа, допустим программы Microsoft Word, или веб-страницы, то вам нужно в документ или текстовое поле его и вставлять. Просто в папку вставить не получится.
И наоборот, скопированную папку в документ тоже вы не вставите.
Также будьте осторожны с важной информацией, которую вы скопировали в буфер: если компьютер неожиданно выключится, перезагрузится, или вы случайно забудете и выключите его, то информация из буфера обмана удалиться.
Поэтому сразу же когда что-то поместили в него, ставьте в нужное вам место и сохраните, если это какой-то документ.
Чистить буфер не обязательно, ведь копируя какой-то файл, или текст, он заменяет предыдущий и поэтому память вашего компьютера засорятся не будет.
Ctrl+A |
Выделить всё. Это могут быть все папки, весь текст, или все файлы в папке |
Ctrl+C |
Копировать выделенный документ или документы, файлы в папке |
Ctrl+X |
Вырезать выделенное. Аналогично предыдущему пункту, только вырезаем |
Ctrl+V |
Вставить все скопированные или вырезанное, что находится в буфере обмена |
Возможно среди читателей есть и те, кому хочется узнать, где находится та секретная папка, или то невидимое пространство, называемое буфером обмена.
В операционной системе Windows XP вы можете зайти на диск C, или на тот диск, на котором она находится, затем в папку «Documents and Settings», а дальше в «System 32″, то есть путь такой: «C:/Documents and Settings/System 32″.
Там есть файл (специальная программа) clipbrd.exe, запустив которую, вы можете увидеть что там находиться именно то, что вы скопировали.
Быстрее найти этот файл и запустить вы можете даже не заходя в папку «System 32″, а просто войти в меню «Пуск» > «Выполнить», ввести clipbrd.exe и нажать клавишу ввода.
Сейчас приведу пример работы этой программы. Я выделю фрагмент текста и нажму «копировать».
.NET Framework 4.5
Другие версии
Эта тема еще не получила оценку - Оценить эту тему
Класс Clipboard предоставляет методы, которые можно использовать для взаимодействия с функцией буфера обмена операционной системы Windows.Многие приложения используют буфер обмена в качестве временного хранилища данных. Например, текстовые процессоры используют буфер обмена во время операций вырезания и вставки. Буфер обмена также полезен для передачи данных из одного приложения в другое.
При добавлении данных в буфер обмена можно указать формат данных таким образом, чтобы другие приложения могли распознать данные, если они могут использовать этот формат. Можно также добавить данные в буфер обмена в нескольких различных форматах, чтобы увеличить количество других приложений, которые потенциально могут использовать данные.
Формат буфера обмена является строкой, которая определяет формат таким образом, чтобы приложение, использующее этот формат, могло получать связанные данные. Класс DataFormats предоставляет предварительно определенные имена форматов для использования. Можно также использовать собственные имена форматов или использовать тип объекта в качестве его формата.
Чтобы добавить данные в буфер обмена в одном или нескольких форматах, используйте метод SetDataObject. Этому методу можно передать любой объект, но для добавления данных в нескольких форматах необходимо сначала добавить данные в отдельный объект, предназначенный для работы с несколькими форматами данных. Обычно данные добавляются к объекту DataObject, но можно использовать любой тип, реализующий интерфейсIDataObject.
В .NET Framework 2.0 можно добавить данные непосредственно в буфер обмена с помощью новых методов, позволяющих упростить основные задачи при работе с буфером обмена. Используйте эти методы при работе с данными в одном общем формате, такими как текст.
Примечание |
Все приложения Windows используют один буфер обмена. Поэтому содержимое буфера обмена может изменяться при переходе к другому приложению. Класс Clipboard может использоваться только в потоках в режиме однопотокового подразделения. Чтобы использовать этот класс, убедитесь, что используемый метод Main помечен атрибутом STAThreadAttribute. Для помещения в буфер обмена объект должен быть сериализуемым. Чтобы сделать тип сериализуемым, его необходимо пометить атрибутомSerializableAttribute. Если методу буфера обмена передается не сериализуемый объект, метод завершится неудачей без создания исключения.Дополнительные сведений о сериализации см. в разделе System.Runtime.Serialization. |
C#
VB
// Demonstrates SetAudio, ContainsAudio, and GetAudioStream.
public System.IO.Stream SwapClipboardAudio(
System.IO.Stream replacementAudioStream)
{
System.IO.Stream returnAudioStream = null;
if (Clipboard.ContainsAudio())
{
returnAudioStream = Clipboard.GetAudioStream();
Clipboard.SetAudio(replacementAudioStream);
}
return returnAudioStream;
}
// Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList
public System.Collections.Specialized.StringCollection
SwapClipboardFileDropList(
System.Collections.Specialized.StringCollection replacementList)
{
System.Collections.Specialized.StringCollection returnList = null;
if (Clipboard.ContainsFileDropList())
{
returnList = Clipboard.GetFileDropList();
Clipboard.SetFileDropList(replacementList);
}
return returnList;
}
// Demonstrates SetImage, ContainsImage, and GetImage.
public System.Drawing.Image SwapClipboardImage(
System.Drawing.Image replacementImage)
{
System.Drawing.Image returnImage = null;
if (Clipboard.ContainsImage())
{
returnImage = Clipboard.GetImage();
Clipboard.SetImage(replacementImage);
}
return returnImage;
}
// Demonstrates SetText, ContainsText, and GetText.
public String SwapClipboardHtmlText(String replacementHtmlText)
{
String returnHtmlText = null;
if (Clipboard.ContainsText(TextDataFormat.Html))
{
returnHtmlText = Clipboard.GetText(TextDataFormat.Html);
Clipboard.SetText(replacementHtmlText, TextDataFormat.Html);
}
return returnHtmlText;
}
Можно также использовать предварительно определенные имена форматов с помощью метода SetData. Дополнительные сведения см. в разделеDataFormats.
C#
VB
// Demonstrates SetData, ContainsData, and GetData
// using a custom format name and a business object.
public Customer TestCustomFormat
{
get
{
Clipboard.SetData("CustomerFormat", new Customer("Customer Name"));
if (Clipboard.ContainsData("CustomerFormat"))
{
return Clipboard.GetData("CustomerFormat") as Customer;
}
return null;
}
}
...
[Serializable]
public class Customer
{
private string nameValue = string.Empty;
public Customer(String name)
{
nameValue = name;
}
public string Name
{
get { return nameValue; }
set { nameValue = value; }
}
}
C#
VB
// Demonstrates how to use a DataObject to add
// data to the Clipboard in multiple formats.
public void TestClipboardMultipleFormats()
{
DataObject data = new DataObject();
// Add a Customer object using the type as the format.
data.SetData(new Customer("Customer as Customer object"));
// Add a ListViewItem object using a custom format name.
data.SetData("CustomFormat",
new ListViewItem("Customer as ListViewItem"));
Clipboard.SetDataObject(data);
DataObject retrievedData = (DataObject)Clipboard.GetDataObject();
if (retrievedData.GetDataPresent("CustomFormat"))
{
ListViewItem item =
retrievedData.GetData("CustomFormat") as ListViewItem;
if (item != null)
{
MessageBox.Show(item.Text);
}
}
if (retrievedData.GetDataPresent(typeof(Customer)))
{
Customer customer =
retrievedData.GetData(typeof(Customer)) as Customer;
if (customer != null)
{
MessageBox.Show(customer.Name);
}
}
}
...
[Serializable]
public class Customer
{
private string nameValue = string.Empty;
public Customer(String name)
{
nameValue = name;
}
public string Name
{
get { return nameValue; }
set { nameValue = value; }
}
}
.NET Framework 4.5
Другие версии
Эта тема еще не получила оценку - Оценить эту тему
Пользовательские операции перетаскивания в приложении Windows можно включить, обрабатывая последовательность событий, которая, как правило, включает события DragEnter, DragLeave и DragDrop.
Можно также реализовать поддержку вырезания/копирования/вставки и передачу данных пользователя в буфер обмена в Windows-приложения с помощью вызова простых методов.
В этом подразделе
Пример. Выполнение операции перетаскивания в Windows Forms
Содержит объяснение того, как начать операцию перетаскивания.
Практическое руководство. Выполнение операции перетаскивания между приложениями
Примеры способов выполнения операций перетаскивания между приложениями.
Практическое руководство. Добавление данных в буфер обмена
Содержит описание способа вставки данных в буфер обмена программными средствами.
Практическое руководство. Извлечение данных из буфера обмена
Описание способов доступа к данным, хранящимся в буфере обмена.
Связанные подразделы
Функциональная возможность перетаскивания в Windows Forms
Описывает методы, события и классы, используемые для реализации перетаскивания.
QueryContinueDrag
Описание структуры события, с помощью которого запрашивается разрешение на продолжение операции перетаскивания.
DoDragDrop
Описание структуры метода, который необходим для начала операции перетаскивания.
Clipboard
Topic |
Location |
Практическое руководство. Отправка данных в активную дочернюю MDI-форму |
Программирование Windows Forms |
Практическое руководство. Отправка данных в активную дочернюю MDI-форму |
dv_ManCli |
Практическое руководство. Отправка данных в активную дочернюю MDI-форму |
dv_ManCli |
.NET Framework 4.5
Другие версии
Эта тема еще не получила оценку - Оценить эту тему
Windows Forms включает набор методов, событий и классов, реализующих поведение перетаскивания. В этом разделе приводится обзор поддержки перетаскивания в Windows Forms.
Выполнение операций перетаскивания
Для выполнения операции перетаскивания используйте метод DoDragDrop класса Control. Дополнительные сведения о том, как выполняется операция перетаскивания, см. в разделе DoDragDrop. Для получения прямоугольника, над которым должен быть перемещен указатель мыши перед началом операции перетаскивания, используется свойство DragSize класса SystemInformation.
События, относящиеся к операциям перетаскивания
В операции перетаскивания имеется две категории событий: события, возникающие в текущей цели операции перетаскивания, и события, возникающие в источнике операции перетаскивания.
В приведенной ниже таблице содержатся события, возникающие в текущей цели операции перетаскивания.
Событие мыши |
Описание |
DragEnter |
Событие происходит при перемещении объекта внутрь границ элемента управления. Обработчик этого события получает аргумент типа DragEventArgs. |
DragOver |
Это событие происходит, когда объект перетаскивается во время расположения указателя мыши в пределах границ элемента управления. Обработчик этого события получает аргумент типа DragEventArgs. |
DragDrop |
Это событие возникает после завершения операции перетаскивания. Обработчик этого события получает аргумент типа DragEventArgs. |
DragLeave |
Событие возникает при перемещении объекта за границы элемента управления. Обработчик этого события получает аргумента типаEventArgs. |
В классе DragEventArgs содержится расположение указателя мыши, текущее состояние кнопок мыши и клавиш CTRL, SHIFT и ALT, перетаскиваемые данные и значения DragDropEffects, которые указывают, какие операции допускаются источником события перетаскивания и результат перетаскивания на цель для операции.
В следующей таблице приведены события, возникающие в источнике операции перетаскивания.
Событие мыши |
Описание |
GiveFeedback |
Это событие возникает во время операции перетаскивания. Оно предоставляет возможность дать пользователю визуальную подсказку о том, что происходит операция перетаскивания, в виде, например, изменения указателя мыши. Обработчик этого события получает аргумент типа GiveFeedbackEventArgs. |
QueryContinueDrag |
Это событие возникает во время операции перетаскивания и позволяет источнику перетаскиваемого объекта определить, следует ли отменить эту операцию. Обработчик этого события получает аргумент типа QueryContinueDragEventArgs. |
В классе QueryContinueDragEventArgs содержится текущее состояние кнопок мыши и клавиш CTRL, SHIFT и ALT, значение, указывающее, была ли нажата клавиша ESC, и значение DragAction, которое может быть установлено для указания того, следует ли продолжать операцию перетаскивания.
.NET Framework 4.5
Другие версии
Эта тема еще не получила оценку - Оценить эту тему
Происходит во время операции перетаскивания и позволяет источнику перетаскивания определить, следует ли отменить эту операцию.
Пространство имен: System.Windows.Forms
Сборка: System.Windows.Forms (в System.Windows.Forms.dll)
Синтаксис
C#
C++
F#
VB
public event QueryContinueDragEventHandler QueryContinueDrag
Заметки
Событие QueryContinueDrag происходит при изменении состояния клавиатуры или кнопки мыши во время операции перетаскивания. СобытиеQueryContinueDrag позволяет источнику операции перетаскивания определить, следует ли отменить эту операцию.
Далее описывается, как и когда вызываются события, связанные с операциями перетаскивания.
Метод DoDragDrop определяет элемент управления при текущем местоположении курсора. Затем он проверяет, является ли элемент управления допустимым для конечного местоположения объекта перетаскивания.
Если элемент управления является допустимым для конечного местоположения объекта перетаскивания, вызывается событие GiveFeedback с указанным эффектом перетаскивания. Список эффектов перетаскивания см. в перечислении DragDropEffects.
Отслеживаются изменения позиции курсора мыши, состояния клавиатуры и кнопки мыши.
При изменении состояния клавиатуры или кнопки мыши происходит событие QueryContinueDrag, определяющее, следует ли продолжить или завершить перетаскивание либо отменить операцию на основании значения свойства Action аргумента QueryContinueDragEventArgs данного события.
Примечание |
События DragOver и GiveFeedback объединены в пару, чтобы при перемещении мыши над конечным местоположением перетаскивания отображались самые последние сведения о расположении мыши. |
По умолчанию событие QueryContinueDrag задает для свойства Action значение Cancel в объекте DragAction, если была нажата клавиша ESC, и задает для свойства Action значение Drop в объекте DragAction, если была нажата левая, средняя или правая кнопка мыши.
Дополнительные сведения об обработке событий см. в разделе Прием событий.
Примеры
В следующем примере кода показана операция перетаскивания между двумя элементами управления ListBox. В примере во время запуска действия перетаскивания вызывается метод DoDragDrop. Действие перетаскивания начинается, если во время события MouseDown мышь сместилась относительно своего положения больше чем на SystemInformation.DragSize. Метод IndexFromPoint применяется для определения индекса элемента, перетаскиваемого во время события MouseDown.
В этом примере также показывается использование пользовательских курсоров для операции перетаскивания. В данном примере требуется, чтобы в каталоге приложения имелось два файла курсоров: 3dwarro.cur и 3dwno.cur первый для пользовательского курсора перетаскивания, а второй для курсора с запрещенным перетаскиванием. Пользовательские курсоры используются, если установлен флажок CheckBoxUseCustomCursorsCheck.Пользовательские курсоры задаются в обработчике событий GiveFeedback.
Состояние клавиатуры проверяется в обработчике события DragOver для правого элемента ListBox, чтобы на основании состояния клавиш SHIFT, CTRL, ALT или сочетания клавиш CTRL+ALT определить, какая операция перетаскивания будет выполнена. Расположение в элементе управленияListBox, куда будет перемещен объект, также определяется во время события DragOver. Если перетаскиваемые данные не относятся к типу String, для свойства DragEventArgs.Effect задается значение None в объекте DragDropEffects. Наконец, состояние перетаскивания отображается в объектеLabelDropLocationLabel.
Данные, перетаскиваемые в правый элемент управления ListBox, определяются в обработчике событий DragDrop, и значение типа String добавляется в соответствующее место списка ListBox. Если перетаскиваемый объект перемещается за пределы формы, то операция перетаскивания отменяется в обработчике событий QueryContinueDrag.
В данном фрагменте кода показано использование события QueryContinueDrag. Полный пример кода см. в описании метода DoDragDrop.
C#
C++
VB
private void ListDragSource_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e) {
// Cancel the drag if the mouse moves off the form.
ListBox lb = sender as ListBox;
if (lb != null) {
Form f = lb.FindForm();
// Cancel the drag if the mouse moves off the form. The screenOffset
// takes into account any desktop bands that may be at the top or left
// side of the screen.
if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom)) {
e.Action = DragAction.Cancel;
}
}
}
Сведения о версии
.NET Framework
Поддерживается в версиях: 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0
.NET Framework (клиентский профиль)
Поддерживается в версиях: 4, 3.5 с пакетом обновления 1 (SP1)
Платформы
Windows 8, Windows Server 2012, Windows 7, Windows Vista с пакетом обновления 2 (SP2), Windows Server 2008 (роль основных серверных компонентов не поддерживается), Windows Server 2008 R2 (роль основных серверных компонентов поддерживается в пакете обновления 1 (SP1) или выше; системы на базе Itanium не поддерживаются)
.NET Framework поддерживает не все версии каждой платформы. Поддерживаемые версии перечислены в разделе Требования к системе для .NET Framework.
.NET Framework 4.5
Другие версии
Эта тема еще не получила оценку - Оценить эту тему
Начинает операцию перетаскивания.
Пространство имен: System.Windows.Forms
Сборка: System.Windows.Forms (в System.Windows.Forms.dll)
Синтаксис
C#
C++
F#
VB
[UIPermissionAttribute(SecurityAction.Demand, Clipboard = UIPermissionClipboard.OwnClipboard)]
public DragDropEffects DoDragDrop(
Object data,
DragDropEffects allowedEffects
)
Параметры
data
Тип: System.Object
Перетаскиваемые данные.
allowedEffects
Тип: System.Windows.Forms.DragDropEffects
Одно из значений DragDropEffects.
Возвращаемое значение
Тип: System.Windows.Forms.DragDropEffects
Значение перечисления DragDropEffects, представляющее конечный результат выполнения операции перетаскивания.
Заметки
Параметр allowedEffects определяет, какие операции перетаскивания возможны. Если операции перетаскивания требуется взаимодействие с приложениями в другом процессе, данные должны быть либо экземпляром базового управляемого класса (String, Bitmap или Metafile), либо объектом, реализующим ISerializable или IDataObject.
Далее описывается, как и когда вызываются события, связанные с операциями перетаскивания.
Метод DoDragDrop определяет элемент управления при текущем местоположении курсора. Затем он проверяет, является ли элемент управления допустимым для конечного местоположения объекта перетаскивания.
Если элемент управления является допустимым для конечного местоположения объекта перетаскивания, вызывается событие GiveFeedback с указанным эффектом перетаскивания. Список эффектов перетаскивания см. в перечислении DragDropEffects.
Отслеживаются изменения позиции курсора мыши, состояния клавиатуры и кнопки мыши.
При изменении состояния клавиатуры или кнопки мыши происходит событие QueryContinueDrag, определяющее, следует ли продолжить или завершить перетаскивание либо отменить операцию на основании значения свойства Action аргумента QueryContinueDragEventArgs данного события.
Примечание |
События DragOver и GiveFeedback объединены в пару, чтобы при перемещении мыши над конечным местоположением перетаскивания отображались самые последние сведения о расположении мыши. |
Примечание |
Метод DoDragDrop фиксирует все исключения и отображает повторно только следующие исключения безопасности или критические исключения: |
Примеры
В следующем примере кода показана операция перетаскивания между двумя элементами управления ListBox. В примере во время запуска действия перетаскивания вызывается метод DoDragDrop. Действие перетаскивания начинается, если во время события MouseDown мышь сместилась относительно своего положения больше чем на SystemInformation.DragSize. Метод IndexFromPoint применяется для определения индекса элемента, перетаскиваемого во время события MouseDown.
В этом примере также показывается использование пользовательских курсоров для операции перетаскивания. В данном примере требуется, чтобы в каталоге приложения имелось два файла курсоров: 3dwarro.cur и 3dwno.cur первый для пользовательского курсора перетаскивания, а второй для курсора с запрещенным перетаскиванием. Пользовательские курсоры используются, если установлен флажок CheckBoxUseCustomCursorsCheck.Пользовательские курсоры задаются в обработчике событий GiveFeedback.
Состояние клавиатуры проверяется в обработчике события DragOver для правого элемента ListBox, чтобы на основании состояния клавиш SHIFT, CTRL, ALT или сочетания клавиш CTRL+ALT определить, какая операция перетаскивания будет выполнена. Расположение в элементе управленияListBox, куда будет перемещен объект, также определяется во время события DragOver. Если перетаскиваемые данные не относятся к типу String, для свойства DragEventArgs.Effect задается значение None в объекте DragDropEffects. Наконец, состояние перетаскивания отображается в объектеLabelDropLocationLabel.
Данные, перетаскиваемые в правый элемент управления ListBox, определяются в обработчике событий DragDrop, и значение типа String добавляется в соответствующее место списка ListBox. Если перетаскиваемый объект перемещается за пределы формы, то операция перетаскивания отменяется в обработчике событий QueryContinueDrag.
C#
C++
VB
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Snip_DragNDrop
{
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.ListBox ListDragSource;
private System.Windows.Forms.ListBox ListDragTarget;
private System.Windows.Forms.CheckBox UseCustomCursorsCheck;
private System.Windows.Forms.Label DropLocationLabel;
private int indexOfItemUnderMouseToDrag;
private int indexOfItemUnderMouseToDrop;
private Rectangle dragBoxFromMouseDown;
private Point screenOffset;
private Cursor MyNoDropCursor;
private Cursor MyNormalCursor;
/// The main entry point for the application.
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
this.ListDragSource = new System.Windows.Forms.ListBox();
this.ListDragTarget = new System.Windows.Forms.ListBox();
this.UseCustomCursorsCheck = new System.Windows.Forms.CheckBox();
this.DropLocationLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
// ListDragSource
this.ListDragSource.Items.AddRange(new object[] {"one", "two", "three", "four",
"five", "six", "seven", "eight",
"nine", "ten"});
this.ListDragSource.Location = new System.Drawing.Point(10, 17);
this.ListDragSource.Size = new System.Drawing.Size(120, 225);
this.ListDragSource.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ListDragSource_MouseDown);
this.ListDragSource.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.ListDragSource_QueryContinueDrag);
this.ListDragSource.MouseUp += new System.Windows.Forms.MouseEventHandler(this.ListDragSource_MouseUp);
this.ListDragSource.MouseMove += new System.Windows.Forms.MouseEventHandler(this.ListDragSource_MouseMove);
this.ListDragSource.GiveFeedback += new System.Windows.Forms.GiveFeedbackEventHandler(this.ListDragSource_GiveFeedback);
// ListDragTarget
this.ListDragTarget.AllowDrop = true;
this.ListDragTarget.Location = new System.Drawing.Point(154, 17);
this.ListDragTarget.Size = new System.Drawing.Size(120, 225);
this.ListDragTarget.DragOver += new System.Windows.Forms.DragEventHandler(this.ListDragTarget_DragOver);
this.ListDragTarget.DragDrop += new System.Windows.Forms.DragEventHandler(this.ListDragTarget_DragDrop);
this.ListDragTarget.DragEnter += new System.Windows.Forms.DragEventHandler(this.ListDragTarget_DragEnter);
this.ListDragTarget.DragLeave += new System.EventHandler(this.ListDragTarget_DragLeave);
// UseCustomCursorsCheck
this.UseCustomCursorsCheck.Location = new System.Drawing.Point(10, 243);
this.UseCustomCursorsCheck.Size = new System.Drawing.Size(137, 24);
this.UseCustomCursorsCheck.Text = "Use Custom Cursors";
// DropLocationLabel
this.DropLocationLabel.Location = new System.Drawing.Point(154, 245);
this.DropLocationLabel.Size = new System.Drawing.Size(137, 24);
this.DropLocationLabel.Text = "None";
// Form1
this.ClientSize = new System.Drawing.Size(292, 270);
this.Controls.AddRange(new System.Windows.Forms.Control[] {this.ListDragSource,
this.ListDragTarget, this.UseCustomCursorsCheck,
this.DropLocationLabel});
this.Text = "drag-and-drop Example";
this.ResumeLayout(false);
}
private void ListDragSource_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Get the index of the item the mouse is below.
indexOfItemUnderMouseToDrag = ListDragSource.IndexFromPoint(e.X, e.Y);
if (indexOfItemUnderMouseToDrag != ListBox.NoMatches) {
// Remember the point where the mouse down occurred. The DragSize indicates
// the size that the mouse can move before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width /2),
e.Y - (dragSize.Height /2)), dragSize);
} else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void ListDragSource_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) {
// Reset the drag rectangle when the mouse button is raised.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void ListDragSource_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left) {
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y)) {
// Create custom cursors for the drag-and-drop operation.
try {
MyNormalCursor = new Cursor("3dwarro.cur");
MyNoDropCursor = new Cursor("3dwno.cur");
} catch {
// An error occurred while attempting to load the cursors, so use
// standard cursors.
UseCustomCursorsCheck.Checked = false;
}finally {
// The screenOffset is used to account for any desktop bands
// that may be at the top or left side of the screen when
// determining when to cancel the drag drop operation.
screenOffset = SystemInformation.WorkingArea.Location;
// Proceed with the drag-and-drop, passing in the list item.
DragDropEffects dropEffect = ListDragSource.DoDragDrop(ListDragSource.Items[indexOfItemUnderMouseToDrag], DragDropEffects.All | DragDropEffects.Link);
// If the drag operation was a move then remove the item.
if (dropEffect == DragDropEffects.Move) {
ListDragSource.Items.RemoveAt(indexOfItemUnderMouseToDrag);
// Selects the previous item in the list as long as the list has an item.
if (indexOfItemUnderMouseToDrag > 0)
ListDragSource.SelectedIndex = indexOfItemUnderMouseToDrag -1;
else if (ListDragSource.Items.Count > 0)
// Selects the first item.
ListDragSource.SelectedIndex =0;
}
// Dispose of the cursors since they are no longer needed.
if (MyNormalCursor != null)
MyNormalCursor.Dispose();
if (MyNoDropCursor != null)
MyNoDropCursor.Dispose();
}
}
}
}
private void ListDragSource_GiveFeedback(object sender, System.Windows.Forms.GiveFeedbackEventArgs e)
{
// Use custom cursors if the check box is checked.
if (UseCustomCursorsCheck.Checked) {
// Sets the custom cursor based upon the effect.
e.UseDefaultCursors = false;
if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move)
Cursor.Current = MyNormalCursor;
else
Cursor.Current = MyNoDropCursor;
}
}
private void ListDragTarget_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
// Determine whether string data exists in the drop data. If not, then
// the drop effect reflects that the drop cannot occur.
if (!e.Data.GetDataPresent(typeof(System.String))) {
e.Effect = DragDropEffects.None;
DropLocationLabel.Text = "None - no string data.";
return;
}
// Set the effect based upon the KeyState.
if ((e.KeyState & (8+32)) == (8+32) &&
(e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link) {
// KeyState 8 + 32 = CTL + ALT
// Link drag-and-drop effect.
e.Effect = DragDropEffects.Link;
} else if ((e.KeyState & 32) == 32 &&
(e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link) {
// ALT KeyState for link.
e.Effect = DragDropEffects.Link;
} else if ((e.KeyState & 4) == 4 &&
(e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) {
// SHIFT KeyState for move.
e.Effect = DragDropEffects.Move;
} else if ((e.KeyState & 8) == 8 &&
(e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) {
// CTL KeyState for copy.
e.Effect = DragDropEffects.Copy;
} else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) {
// By default, the drop action should be move, if allowed.
e.Effect = DragDropEffects.Move;
} else
e.Effect = DragDropEffects.None;
// Get the index of the item the mouse is below.
// The mouse locations are relative to the screen, so they must be
// converted to client coordinates.
indexOfItemUnderMouseToDrop =
ListDragTarget.IndexFromPoint(ListDragTarget.PointToClient(new Point(e.X, e.Y)));
// Updates the label text.
if (indexOfItemUnderMouseToDrop != ListBox.NoMatches){
DropLocationLabel.Text = "Drops before item #" + (indexOfItemUnderMouseToDrop + 1);
} else
DropLocationLabel.Text = "Drops at the end.";
}
private void ListDragTarget_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
// Ensure that the list item index is contained in the data.
if (e.Data.GetDataPresent(typeof(System.String))) {
Object item = (object)e.Data.GetData(typeof(System.String));
// Perform drag-and-drop, depending upon the effect.
if (e.Effect == DragDropEffects.Copy ||
e.Effect == DragDropEffects.Move) {
// Insert the item.
if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
ListDragTarget.Items.Insert(indexOfItemUnderMouseToDrop, item);
else
ListDragTarget.Items.Add(item);
}
}
// Reset the label text.
DropLocationLabel.Text = "None";
}
private void ListDragSource_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e) {
// Cancel the drag if the mouse moves off the form.
ListBox lb = sender as ListBox;
if (lb != null) {
Form f = lb.FindForm();
// Cancel the drag if the mouse moves off the form. The screenOffset
// takes into account any desktop bands that may be at the top or left
// side of the screen.
if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom)) {
e.Action = DragAction.Cancel;
}
}
}
private void ListDragTarget_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) {
// Reset the label text.
DropLocationLabel.Text = "None";
}
private void ListDragTarget_DragLeave(object sender, System.EventArgs e) {
// Reset the label text.
DropLocationLabel.Text = "None";
}
}
}
В следующем примере кода показано использование перечисления DragDropEffects для задания способа передачи данных между элементами управления, вовлеченными в операцию перетаскивания. В данном примере требуется наличия формы, включающей элементы управления RichTextBoxи ListBox, а также элемента управления ListBox, заполненного списком допустимых имен файлов. При перетаскивании имени файла на элемент управления RichTextBox происходит событие DragEnter элемента управления. В обработчике событий свойство Effect объекта DragEventArgsинициализируется в объекте DragDropEffects, чтобы указать, что данные, на которые ссылается путь файла, следует скопировать в элемент управленияRichTextBox.
C#
C++
VB
private void Form1_Load(object sender, EventArgs e)
{
// Sets the AllowDrop property so that data can be dragged onto the control.
richTextBox1.AllowDrop = true;
// Add code here to populate the ListBox1 with paths to text files.
}
private void listBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
// Determines which item was selected.
ListBox lb =( (ListBox)sender);
Point pt = new Point(e.X,e.Y);
int index = lb.IndexFromPoint(pt);
// Starts a drag-and-drop operation with that item.
if(index>=0)
{
lb.DoDragDrop(lb.Items[index].ToString(), DragDropEffects.Link);
}
}
private void richTextBox1_DragEnter(object sender, DragEventArgs e)
{
// If the data is text, copy the data to the RichTextBox control.
if(e.Data.GetDataPresent("Text"))
e.Effect = DragDropEffects.Copy;
}
private void richTextBox1_DragDrop(object sender, DragEventArgs e)
{
// Loads the file into the control.
richTextBox1.LoadFile((String)e.Data.GetData("Text"), System.Windows.Forms.RichTextBoxStreamType.RichText);
}
Сведения о версии
.NET Framework
Поддерживается в версиях: 4.5, 4, 3.5, 3.0, 2.0, 1.1, 1.0
.NET Framework (клиентский профиль)
Поддерживается в версиях: 4, 3.5 с пакетом обновления 1 (SP1)
Платформы
Windows 8, Windows Server 2012, Windows 7, Windows Vista с пакетом обновления 2 (SP2), Windows Server 2008 (роль основных серверных компонентов не поддерживается), Windows Server 2008 R2 (роль основных серверных компонентов поддерживается в пакете обновления 1 (SP1) или выше; системы на базе Itanium не поддерживаются)
.NET Framework поддерживает не все версии каждой платформы. Поддерживаемые версии перечислены в разделе Требования к системе для .NET Framework.