This project has moved. For the latest updates, please go here.

Nicenis has moved to GitHub: https://github.com/Nicenis/Nicenis

Introduction

DragSource is a static class that helps to make a draggable element for drag-and-drop operation.

Requirements

You have to reference the Nicenis.dll.

Basic Usage

Two attached properties are required to be set at a minimum.
  • AllowDrag: Indicating whether the element is draggable.
  • Data: A data object that contains the data being dragged.
This is an example.

<Window
    x:Class="DragSourceSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:n="clr-namespace:Nicenis.Windows;assembly=Nicenis"
    Title="MainWindow" Height="200" Width="200">

    <!-- This border will be draggable.-->
    <Border
        n:DragSource.AllowDrag="True"
        n:DragSource.Data="Test Data"
        Margin="30"
        Background="Green"
        />
</Window>

It will look like this image if you drag the border.

Nicenis.Windows.DragSource Sample Image.png

The position you click in the border is not preserved by default when it is dragged. You can use the following attached properties to solve it.
  • VisualFeedbackOffset: An offset that is pointed by a pointing device in the visual drag feedback.
  • ContactPosition: A readonly contact position in the dragged source.
This is a refined example.

<Window
    x:Class="DragSourceSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:n="clr-namespace:Nicenis.Windows;assembly=Nicenis"
    Title="MainWindow" Height="200" Width="200">

    <!-- This border will be draggable.-->
    <Border
        n:DragSource.AllowDrag="True"
        n:DragSource.Data="Test Data"
        n:DragSource.VisualFeedbackOffset="{Binding (n:DragSource.ContactPosition), RelativeSource={RelativeSource Self}}"
        Margin="30"
        Background="Green"
        />
</Window>

Download the sample project

Lazy Data Object Creation

You can set the Data attached property to an implementation of the IDataObjectProvider interface.

namespace Nicenis.Windows
{
    /// <summary>
    /// Provides a way to get a data object that contains the data being dragged.
    /// </summary>
    public interface IDataObjectProvider
    {
        /// <summary>
        /// Gets a data object that contains the data being dragged.
        /// </summary>
        /// <returns>A data object that contains the data being dragged.</returns>
        object GetDataObject();
    }
}

The GetDataObject method is called right before the drag-and-drop is started. A sample implementation is as follows.

/// <summary>
/// A sample data context that implements the IDataObjectProvider interface.
/// </summary>
public class SampleDataContext : IDataObjectProvider
{
    public object GetDataObject()
    {
        return "Test Data";
    }
}

The following code shows how to bind it to a Data attached property.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // Initializes the DataContext.
        DataContext = new SampleDataContext();
    }
}

<Window
    x:Class="DragSourceSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:n="clr-namespace:Nicenis.Windows;assembly=Nicenis"
    Title="MainWindow" Height="200" Width="200">

    <!-- The Data is bound to an implementation of the IDataObjectProvider interface.-->
    <Border
        n:DragSource.AllowDrag="True"
        n:DragSource.Data="{Binding}"
        n:DragSource.VisualFeedbackOffset="{Binding (n:DragSource.ContactPosition), RelativeSource={RelativeSource Self}}"
        Margin="30"
        Background="Green"
        />
</Window>

Download the sample project

Custom Visual Feedback

If you need to customize the dragged image called visual feedback, you can use the VisualFeedback attached property.
  • VisualFeedback: The content of the visual drag feedback.
The following code uses an ellipse as a custom visual feedback.

<Window
    x:Class="DragSourceSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:n="clr-namespace:Nicenis.Windows;assembly=Nicenis"
    Title="MainWindow" Height="200" Width="200"
    >
    <Border
        n:DragSource.AllowDrag="True"
        n:DragSource.Data="Test Data"
        n:DragSource.VisualFeedbackOffset="70 70"
        Margin="30"
        Background="Green"
        >
        <!-- An ellipsis is set as a visual feedback.-->
        <n:DragSource.VisualFeedback>
            <Ellipse Fill="Red" Width="140" Height="140" />
        </n:DragSource.VisualFeedback>
    </Border>
</Window>

It will look like the following if you drag the border.

Nicenis.Windows.DragSource Sample Image - Custom Visual Feedback.png

Download the sample project

Visual feedback inherits data source's DataContext by default. You can override it by using the following attached property.
  • VisualFeedbackDataContext: An object that is set to the data context of the visual drag feedback.
If you want visual feedback templating, the following attached properties may help you.
  • VisualFeedbackTemplate: A data template for the content of the visual drag feedback.
  • VisualFeedbackTemplateSelector: A template selector for the content of the visual drag feedback.

Events

DragSouce raises several routed events with preview events during drag operation. The first is the DragSensing event. It is raised when user starts some action that can initiate a drag operation.
  • DragSensing: The routed event that is raised when drag gesture recognition is in progress.
It is a cancelable event. If you set the Cancel property of the event arguments to true, it prevents drag operation.

private void Border_DragSensing(object sender, DragSourceDragSensingEventArgs e)
{
    // Prevents starting drag operation.
    e.Cancel = true;
}

When a drag gesture is recognized, a Dragging event is raised before starting a drag operation.
  • Dragging: The routed event that is raised when a dragging is about to start.
It is also a cancelable event like DragSensing. The event arguments provides various properties that are similar to DragSource's attached properties. So you can use it to override most values set by DragSource's attached properties. It allows you to create a data object in a Dragging event handler instead of XAML.

private void Border_Dragging(object sender, DragSourceDraggingEventArgs e)
{
    // Sets a data object that contains the data being dragged.
    e.Data = "The Data";
}

If a drag operation is started, GiveFeedback and QueryContinueDrag event are raised periodically.
  • GiveFeedback: The routed event that is raised when the DragDrop.GiveFeedback event is raised.
  • QueryContinueDrag: The routed event that is raised that is raised when the DragDrop.QueryContinueDrag event is raised.
As you can see in the above description, these events are just wrapper events. It just provides additional properties related to DragSource. The following updates VisualFeedback to show the current time.

private void Border_GiveFeedback(object sender, DragSourceGiveFeedbackEventArgs e)
{
    // Sets the visual feedback to the current time.
    e.VisualFeedback = DateTime.Now.ToString();
}

When a drag operation is over, a Dragged event is raised.
  • Dragged: The routed event that is raised when a drag-and-drop operation is finished.
You can use the FinalEffects property of the event arguments to check how a drag operation is finished.

private void Border_Dragged(object sender, DragSourceDraggedEventArgs e)
{
    if (e.FinalEffects == DragDropEffects.Copy)
    {
        // The dragged data is copied.
    }
    
    if (e.FinalEffects == DragDropEffects.Move)
    {
        // The dragged data is moved.
    }   
}

Touch Not Ready

This class is not tested in a touch device yet.

Last edited Dec 31, 2016 at 8:15 PM by Ryeol, version 11

Comments

No comments yet.