Перетаскивание (Drag and Drop)

68

Операции перетаскивания (способ извлечения информации из одного места в окне и помещения ее в другое место) сегодня не являются столь распространенными, как несколько лет назад. Программисты постепенно перешли на другие методы копирования информации, которые не требуют удержания нажатой кнопки мыши (многим пользователям это удается с трудом). Программы, которые поддерживают перетаскивание, часто предлагают его как быстрый вариант для опытных пользователей, а не как стандартный способ работы.

Операции перетаскивания в WPF не претерпели существенных изменений. Если вы использовали их в приложениях Windows Forms, то увидите, что программный интерфейс в WPF остался практически таким же. Ключевым отличием является то, что методы и события, используемые в операциях перетаскивания, сосредоточены в классе System.Windows.DragDrop и через него доступны другим классам (например, UIElement).

По сути, операция перетаскивания выполняется в три этапа:

Вы можете попробовать, как работает перетаскивание, добавив в окно два объекта TextBox, т.к. элемент TextBox имеет встроенную логику для поддержки операции перетаскивания. Если выбрать фрагмент текста внутри текстового поля, то его можно перетащить в другое текстовое поле. Когда вы отпустите кнопку мыши, текст будет перемещен. Те же принципы распространяются и на взаимодействие приложений — например, можно перетащить кусок текста из документа Word в объект WPF TextBox, или наоборот.

Иногда бывает необходимо разрешить перетаскивание между элементами, не обладающими такой встроенной возможностью. Например, нужно сделать так, чтобы пользователь мог перетаскивать содержимое из текстового поля на метку. В такой ситуации придется обрабатывать события перетаскивания:

<Canvas>
        <Label Name="lbl2" Canvas.Top="100" Canvas.Left="30" Padding="10"
               BorderBrush="LightBlue" BorderThickness="2" MouseDown="lbl1_MouseDown">Всем пока (</Label>
        <Label Name="lbl1" Canvas.Top="40" Canvas.Left="30" Padding="10"
               BorderBrush="LightBlue" BorderThickness="2" MouseDown="lbl1_MouseDown">Всем привет!</Label>
        <Border Canvas.Top="75" Canvas.Left="250" BorderBrush="Black" BorderThickness="2">
            <TextBlock MinWidth="100" MinHeight="30" FontSize="16" 
                       Name="txtTarget" AllowDrop="True" Drop="txtTarget_Drop"></TextBlock>
        </Border>
</Canvas>
public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void lbl1_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Label lbl = (Label)sender;
            DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);
        }

        private void txtTarget_Drop(object sender, DragEventArgs e)
        {
            ((TextBlock)sender).Text = (string)e.Data.GetData(DataFormats.Text);
        }
    }

У операции перетаскивания есть две стороны: источник и цель. Чтобы создать источник перетаскивания, нужно в некоторый момент вызвать метод DragDrop.DoDragDrop(), чтобы начать операцию перетаскивания. В этот момент идентифицируется источник для операции перетаскивания, выбирается содержимое, которое нужно переместить, и задаются разрешенные при перетаскивании эффекты (копирование, перемещение и т.д.).

Обычно метод DoDragDrop() вызывается в ответ на событие MouseDown или PreviewMouseDown. Для операции перетаскивания используется текстовое содержимое метки.

Свойство AllowDrop элемента, который принимает данные, должно иметь значение true. Кроме того, этот элемент должен обработать событие Drop, чтобы оперировать данными.

Первая стадия Drag and Drop
Вторая стадия Drag and Drop
Третья стадия Drag and Drop

Когда свойству AllowDrop присваивается значение true, элементу разрешается принимать любой тип информации. Если нужны большие возможности, можно обрабатывать событие DragEnter. В этот момент можно проверить тип перетаскиваемых данных, а затем определить тип разрешаемой операции.

Операция перетаскивания позволяет обмениваться объектами любых типов. Этот вольный подход вполне годится для ваших приложений, но его не рекомендуется применять, если вам нужно сообщаться с другими приложениями. В этом случае следует использовать один из базовых типов данных (например, строки, целые числа и т.п.) или объект, который реализует интерфейс ISerializable или IDataObject (что позволит .NET передавать ваш объект в виде потока байтов и заново создавать объект в домене другого приложения). Интересным приемом является преобразование элемента WPF в XAML с последующей его реконструкцией в другом месте. Все, что для этого нужно — объекты XamlWriter и XamlReader.

Пройди тесты
Лучший чат для C# программистов