Basically this:
public class MultiSelectEditInteractiveOverlay : EditInteractiveOverlay
{
private PointStyle controlPointStyle;
private PointStyle selectedControlPointStyle;
private PointShape startPoint;
Collection<int> ids;
public MultiSelectEditInteractiveOverlay()
: base()
{
this.CanAddVertex = false;
this.CanDrag = true;
this.CanRemoveVertex = false;
this.CanResize = false;
this.CanRotate = false;
ids = new Collection<int>();
}
public PointStyle ControlPointStyle
{
get { return controlPointStyle; }
set { controlPointStyle = value; }
}
public PointStyle SelectedControlPointStyle
{
get { return selectedControlPointStyle; }
set { selectedControlPointStyle = value; }
}
/// <summary>
/// When drag and drop is complete add the shapes to the new location.
/// </summary>
/// <param name="targetPointShape"></param>
protected override void EndEditingCore(PointShape targetPointShape)
{
ClearAllControlPoints();
CalculateCustomAllControlPoints();
ShowAllControlPointLayers(true);
}
/// <summary>
/// Override the mouse enter core from the base.
/// </summary>
/// <param name="interactionArguments"></param>
/// <returns></returns>
protected override InteractiveResult MouseEnterCore(InteractionArguments interactionArguments)
{
var result = base.MouseEnterCore(interactionArguments);
return base.MouseEnterCore(interactionArguments);
}
/// <summary>
/// Process the mouse down click and get all selected features and their starting locations.
/// </summary>
/// <param name="interactionArguments"></param>
/// <returns></returns>
protected override InteractiveResult MouseDownCore(InteractionArguments interactionArguments)
{
InteractiveResult result = base.MouseDownCore(interactionArguments);
startPoint = null;
if (interactionArguments.MouseButton == MapMouseButton.Left)
{
//If there are features selected calculate the starting points.
if (EditShapesLayer.InternalFeatures.Count > 0)
{
//Search are is the entire map for calculating the starting feature location.
RectangleShape searchingArea = new RectangleShape(interactionArguments.WorldX - interactionArguments.SearchingTolerance, interactionArguments.WorldY + interactionArguments.SearchingTolerance, interactionArguments.WorldX + interactionArguments.SearchingTolerance, interactionArguments.WorldY - interactionArguments.SearchingTolerance);
//set the starting points
foreach (Feature feature in DragControlPointsLayer.InternalFeatures)
{
BaseShape shape = feature.GetShape();
if (shape.IsWithin(searchingArea))
{
startPoint = new PointShape(interactionArguments.WorldX, interactionArguments.WorldY);
}
}
//Define the start point used to calculate the location change point.
if (SetSelectedControlPoint(new PointShape(interactionArguments.WorldX, interactionArguments.WorldY), interactionArguments.SearchingTolerance))
{
startPoint = new PointShape(interactionArguments.WorldX, interactionArguments.WorldY);
}
//If no shape defined process base method.
if (startPoint == null)
{
result = base.MouseDownCore(interactionArguments);
}
}
}
return result;
}
/// <summary>
/// Process the mouse move and collect the new location of all features being moved.
/// </summary>
/// <param name="interactionArguments"></param>
/// <returns></returns>
protected override InteractiveResult MouseMoveCore(InteractionArguments interactionArguments)
{
InteractiveResult result = new InteractiveResult();
if (ControlPointType != ControlPointType.None)
{
//If dragging calculate the new feature locations.
if (ControlPointType == ControlPointType.Drag)
{
//If no starting point return the default.
if (startPoint == null)
{
return result;
}
else
{
//Get the current mouse location.
PointShape currentPoint = new PointShape(interactionArguments.WorldX, interactionArguments.WorldY);
double xOffset = currentPoint.X - startPoint.X;
double yOffset = currentPoint.Y - startPoint.Y;
//Create a dictionary to hold the new location of the feature by id.
Dictionary<int, Feature> features = new Dictionary<int, Feature>();
int index = 0;
if (ids.Count == 0)
{
//For each selected feature calculate the new map location using the mouse location in the DragControlPointsLayer.
//Add the new id and new location of the feature to the dictionary.
//This code may create duplicates in the dictionary and it is allow and handled later.
foreach (Feature feature in EditShapesLayer.InternalFeatures)
{
foreach (Feature controlFeature in DragControlPointsLayer.InternalFeatures)
{
PointShape oldPoint = controlFeature.GetShape() as PointShape;
PointShape targetPoint = new PointShape(oldPoint.X + xOffset, oldPoint.Y + yOffset);
features.Add(index, DragFeature(feature, oldPoint, targetPoint));
index++;
}
}
}
//Process the new location dictionary.
foreach (var feature in features)
{
//If the EditShapesLayer contains the feature set the location else add a new one.
//This handles possible duplicates created in the previous step.
if (EditShapesLayer.InternalFeatures.Contains(feature.Value.Id))
{
EditShapesLayer.InternalFeatures[feature.Value.Id] = feature.Value;
}
else
{
EditShapesLayer.InternalFeatures.Add(feature.Value.Id, feature.Value);
}
}
//Clear and set the new locations.
CalculateCustomAllControlPoints();
//Set the start location equal to the current.
startPoint = currentPoint.CloneDeep() as PointShape;
//Redraw the features in the new location.
result.InteractiveOverlayUpdateMode = InteractiveOverlayUpdateMode.Update;
result.ProcessOtherOverlaysMode = ProcessOtherOverlaysMode.DoNotProcessOtherOverlays;
}
}
else
{
result = base.MouseMoveCore(interactionArguments);
}
}
return result;
}
/// <summary>
/// Process the mouse click and set the final feature locations.
/// </summary>
/// <param name="interactionArguments"></param>
/// <returns></returns>
protected override InteractiveResult MouseClickCore(InteractionArguments interactionArguments)
{
InteractiveResult result = base.MouseClickCore(interactionArguments);
//if not InteractiveOverlayUpdateMode.Update then set the final locations and redraw.
if (result.InteractiveOverlayUpdateMode != InteractiveOverlayUpdateMode.Update)
{
//Set the search area as the entire map.
RectangleShape searchingArea = new RectangleShape(interactionArguments.WorldX - interactionArguments.SearchingTolerance, interactionArguments.WorldY + interactionArguments.SearchingTolerance, interactionArguments.WorldX + interactionArguments.SearchingTolerance, interactionArguments.WorldY - interactionArguments.SearchingTolerance);
//Get the current feature locations.
foreach (Feature feature in EditShapesLayer.InternalFeatures)
{
BaseShape shape = feature.GetShape();
//If the feature is on the map and nothing is still being moved set the location and redraw.
if (shape.Intersects(searchingArea) && DragControlPointsLayer.InternalFeatures.Count == 0)
{
//Clear and set the final location.
CalculateCustomAllControlPoints();
//Redraw all features.
result.InteractiveOverlayUpdateMode = InteractiveOverlayUpdateMode.Update;
result.ProcessOtherOverlaysMode = ProcessOtherOverlaysMode.DoNotProcessOtherOverlays;
}
}
}
return result;
}
/// <summary>
/// Set the control points for the map features.
/// </summary>
public void CalculateCustomAllControlPoints()
{
//Clear the current control points.
ClearAllControlPoints();
//Set the controls points by property.
if (CanDrag) { CalculateCustomDragControlPoint(); }
if (CanRotate) { CalculateRotateControlPoints(); }
if (CanResize) { CalculateResizeControlPoints(); }
if (CanReshape) { CalculateVertexControlPoints(); }
//Draw and show the features in the new location.
ShowAllControlPointLayers(true);
}
/// <summary>
/// Make all the control point layers visible.
/// </summary>
/// <param name="visiable"></param>
private void ShowAllControlPointLayers(bool visiable)
{
DragControlPointsLayer.IsVisible = visiable;
RotateControlPointsLayer.IsVisible = visiable;
ResizeControlPointsLayer.IsVisible = visiable;
ExistingControlPointsLayer.IsVisible = visiable;
}
/// <summary>
/// Set the current location of the features.
/// </summary>
protected void CalculateCustomDragControlPoint()
{
LineShape centerPointsLine = new LineShape();
//For each selected feature, set the current location.
foreach (Feature feature in EditShapesLayer.InternalFeatures)
{
//Calculate the new location of the feature.
IEnumerable<Feature> dragControlPoints = CalculateDragControlPointsCore(feature);
BaseShape baseShape = feature.GetShape();
PointShape centerPointShape = baseShape.GetCenterPoint();
//If the center point of the features is not set, set it based on the feature's bounding box.
if (double.IsNaN(centerPointShape.X) || double.IsNaN(centerPointShape.Y) || double.IsInfinity(centerPointShape.X) || double.IsInfinity(centerPointShape.Y))
{
centerPointShape = baseShape.GetBoundingBox().UpperLeftPoint;
}
//Add the feature center point to the list of points.
centerPointsLine.Vertices.Add(new Vertex(centerPointShape));
}
//Set the first feature's center point.
if (centerPointsLine != null && centerPointsLine.Vertices.Count > 0)
{
PointShape centerPointInCenterPoints = new PointShape(centerPointsLine.Vertices[0]);
if (centerPointsLine.Vertices.Count == 2)
{
centerPointInCenterPoints = centerPointsLine.GetCenterPoint();
}
else if (centerPointsLine.Vertices.Count > 2)
{
centerPointInCenterPoints = centerPointsLine.GetBoundingBox().GetCenterPoint();
}
//Add the first feature's center point as the control point.
Feature addedFeature = new Feature(centerPointInCenterPoints);
DragControlPointsLayer.InternalFeatures.Add(addedFeature);
}
}
}