Project Documentation

Basic Objectives

Before the features of the advadev Data Storage component are documented – here an overview on the underlying general concept:

Objective of this component is to extend any UI elements inside the user interface by a drag-drop-functionality. This implies to drag UI elements, move them visually and drop them on a different place. Additional to that it should be possible to execute actions when dropping an UI element. There should be the ability to group different UI elements together so that they can have different states during a drag-drop-action (“is dragged”, “an element of the same group is dragged”, “is below a dragged element”)

The technical solution for that is that the complete area in which drag-drop-actions should happen will be placed in a DragDropContainer control. The actual drag-drop-configuration (“which element belongs to which group”, “which element can be dragged”, “which element is a drop-target”) will be realized by adding attached properties to UI elements. Here the class of the control:

732659

And the XAML code how to use it:
…
xmlns:advadevDragDrop="clr-namespace:advadev.Windows.DragDrop;assembly=advadev.Windows.DragDrop"
…
<advadevDragDrop:DragDropContainer></advadevDragDrop:DragDropContainer>

This control is responsible for the complete drag-drop-action. Because the control is derived from the class “Grid” it is possible to place other controls inside the control as been done for Grids. If this control is missing the complete component will not work!

The individual part features of the component will be described more detailed below (how they can be used and how they are implemented)

Prerequisites to use this component

  • Controls which should be extended by a drag-drop-functionality must be derived from the class FrameworkElement

Notes

  • In the complete documentation we are always talking about „UI elements“. That means in our vocabulary “element in the user interface” – not “controls derived from the class UIElement”. In fact controls must be derived from the class FrameworkElement to be usable 

Feature „Drag-Move-Drop”

This feature contains everything what is necessary to drag a UI element, to move it and to drop it at a different position

First of all a technical description about what happens during a drag-drop-action from the implementation perspective:

1) A UI element will be assigned to a drag-drop-group by setting the attached property DragDropGroupName to a unique name for the group. The associated DragDropContainer control creates for each group name a control of the class DragDropGroup and adds it to its childs. The UI element will be assigned to the matching DragDropGroup control. Below will be explained why a control is required for the group. The configuration of the group name as example code:
<Control ToolTip="My Demo Control"
         …
         advadevDragDrop:DragDropContainer.DragDropGroupName="dragDropGroup1" />

Additional to that the attached property IsDraggable must be set to true so that a UI element can be dragged. The configuration of this flag:
<Control ToolTip="My Demo Control"
         …
         advadevDragDrop:DragDropContainer.IsDraggable="True" />

2) If a DragDropGroup control gets a UI element assigned it registers event handler for different actions: Click of the left mouse button or a touch event. Additional to that the property IsManipulationEnabled of the UI element will be set to true to enable its touch ability

3) In the case that such an event occurs (mouse click or touch start) the actual action starts – the movement of the element. Therefore a TranslateTransform will be added to the dragged UI element as render-transformation. If it already contains a render-transformation this remains attached to the UI element on a lower level (both will be placed in a TransformGroup)

4) While moving around by mouse or touch the mentioned TranslateTransform will be updated corresponding to the movement

5) In the case that the mouse button is released or if the touch ends the transformations will be reset to the original states (of course not until the matching command have been executed as described below)
Theoretically the implementation is complete now – we are able to move a UI element around inside of a predefined area. But if we start the demo application with this implementation we will discover the following effect:

732658

If a UI element of the left upper area is moved and leaves that area to the right it disappears “below” the right upper area. This happens because the right grid is defined after the left grid in the XAML code and the a white background is assigned to it

Of course this is not the desired behavior. A dragged UI element should always be the topmost of all controls. At least it should appear as that for the user! And so the implementation of the control is extended by a little trick:

Once a UI element is dragged we will add another UI element during step 3. And this will be a kind of an inverse shadow. It will be placed precise above the UI element and it will have the precise same look. Therefore a thumb control will be added from the DragDropGroup control as child (this is by the way the reason why to use a control). Because this thumb control is the last one added to the container control it will be the topmost and therefore always visible. To ensure that is has the same appearance as the UI element the following steps are necessary:
  • Its width and height properties are bound to the matching ones of the UI element
  • The same transformations will be assigned to it
  • As background a VisualBrush will be assigned with a reference to the UI element
In order to that it appears for the user as if the UI element itself will be moved around in the user interface:

732657

Notes
  • Without any custom action (e.g. drop command) the dragged UI element will be moved back to its original position after dropping 

Feature „Drop-Commands”

This feature contains everything what is necessary to execute actions while dropping a UI element
The component allows executing commands if a UI element will be dropped. Therefore 3 different options are implemented:
  • A command is assigned to the dragged UI element which should be executed
  • A command is assigned to a UI element which should be executed if another UI element of the same group is dropped above it
  • Commands are assigned to both UI elements
Assigned commands must be of the type DropCommand. This class defines an Execute and a CanExecute method. The argument for those methods is an object of the class DropCommandParameter:

The command gets information by this parameter about:
  • The dragged UI element
  • A parameter defined by the dragged UI element
  • The UI element over which the dragged UI element had been dropped
  • A parameter defined by that element
  • The offset of the movement of the dragged UI element
The configuration of the commands as example code:
<Control ToolTip="My Demo Drag Control"
         …
         advadevDragDrop:DragDropContainer.SourceDropCommand="{Binding …}"
         advadevDragDrop:DragDropContainer.SourceDropCommandParameter="{Binding …}" />
…
<Control ToolTip="My Demo Drop Control"
         …
         advadevDragDrop:DragDropContainer.TargetDropCommand="{Binding …}"
         advadevDragDrop:DragDropContainer.TargetDropCommandParameter="{Binding …}" />

And the implementation of a command as example code:
…
decreaseCounterCommand = new DropCommand(decreaseCounterExecuted, decreaseCounterCanExecute);
…
static private bool decreaseCounterCanExecute(object sender, DropCommandParameter args)
{
    DemoModelItem item = args.DropSourceParameter as DemoModelItem;
    return (item != null && item.Counter > 0 && args.DropTarget != null);
}
…
static private void decreaseCounterExecuted(object sender, DropCommandParameter args)
{
    DemoModelItem item = args.DropSourceParameter as DemoModelItem;
    if (item != null && item.Counter > 0 && args.DropTarget != null)
    {
        item.Counter--;
    }
}
…

Notes
  • The attached property IsDropTarget must be set to true so that a target-drop-command will be executed
  • If a UI element declares a target-drop-command and this is not executable it will be of course not executed. If a UI element will be dropped above it the source command declared by the dragged UI element will be executed with NULL as drop target / drop target parameter

Feature „Drag-Drop-States”

This feature contains everything what is necessary to change the appearance of UI element based on its drag-drop-state
During a drag-drop-action this component sets several attached properties on involved UI elements (UI elements with the same group names) based on the current drag-drop-state. States can be:
  • IsDragged: This property indicates whether a UI element is the dragged one
  • IsDragActive: This property indicates whether a UI element of the same group is dragged
  • IsActiveDropTarget: This property indicates whether a UI element is below the current dragged one and therefore its target command would be executed at dropping
Those attached properties are usable to change the appearance of UI elements. As example using them as triggers in the XAML code:
<Trigger Property="advadevDragDrop:DragDropContainer.IsDragged" Value="True">
        <Setter Property="BorderBrush" Value="Blue" />
    </Trigger><Trigger Property="advadevDragDrop:DragDropContainer.IsDragActive" Value="True">
        <Setter Property="BorderBrush" Value="Orange" />
    </Trigger><Trigger Property="advadevDragDrop:DragDropContainer.IsActiveDropTarget" Value="True">
       <Setter Property="BorderBrush" Value="YellowGreen" />
    </Trigger>

Note
  • If a UI element is dragged its IsDragged attached property AND its IsDragActive property will be set
  • If a UI elements declares a drop-command and this is not executable its IsDragActive attached property will not be set (if it does not declare a drop-command it will be set)

Thomas Gysser | www.advadev.de | advadev.blogspot.de
... advanced development

Last edited Sep 23, 2013 at 10:06 AM by advadev, version 4