/******************************************************************************
* DragHandleConnector.cs
*
* This module implements the code behind for the DragHandleConnector class.
*
* Date: 2/2009
*
* Copyright (c) 2009, Mark Betz
*
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Author nor the names of contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY MARK BETZ ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PART-
* ICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MARK BETZ BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Windows;
namespace DrawControls
{
/// <summary>
/// Delegate type for position coercion callbacks used to
/// adjust DragHandle position properties for consumption
/// by clients
/// </summary>
/// <param name="p">A <see cref="T:System.Windows.Point">Point</see></param>
/// <returns></returns>
public delegate Point CoercePointCallback(Point p);
/// <summary>
/// Enumerates the position axes that should serve as update data
/// for a given client
/// </summary>
public enum SourceAxes
{
/// <summary>
/// Specifies that the X axis will be reported. The
/// implied update type is double.
/// </summary>
X,
/// <summary>
/// Specifies that the Y axis will be reported. The
/// implied update type is double.
/// </summary>
Y,
/// <summary>
/// Specifies that both axes will be reported. The
/// implied update type is Point.
/// </summary>
Both
};
/// <summary>
/// DragHandleTarget encapsulates a single update point from a DragHandle
/// to a client object property. Multiple targets can be defined to send
/// values to multiple properties. This is primarily used to send Point
/// data to a double X/Y pair, as in the case of the Line shape.
/// </summary>
public class DragHandleTarget
{
/// <summary>
/// Constructs a new DragHandle target for the specified property,
/// owner object, and source
/// </summary>
/// <param name="p">A DependencyProperty to be updated when the
/// DragHandle position changes</param>
/// <param name="o">The DependencyObject that owns the property to be updated</param>
/// <param name="s">A value from the <see cref="DrawControls.SourceAxes">SourceAxes</see>
/// enum specifying which axis should be used to update the property.</param>
public DragHandleTarget( DependencyProperty p, DependencyObject o,
SourceAxes s )
{
Property = p;
Owner = o;
Axes = s;
}
/// <summary>
/// The property which this target should update when the DragHandle
/// position changes. It's type must be compatible with the type
/// implied by the Axes property.
/// </summary>
public DependencyProperty Property { get; set; }
/// <summary>
/// The DependencyObject which owns the property to be updated
/// </summary>
public DependencyObject Owner { get; set; }
/// <summary>
/// A value from the <see cref="DrawControls.SourceAxes">SourceAxes</see>
/// enum specifying which axis of handle movement should be used to
/// update the target property.
/// </summary>
public SourceAxes Axes { get; set; }
}
/// <summary>
/// A DragHandleConnection is a list of DragHandleTargets and a callback
/// used to examine and coerce position values before they are reported
/// to a client.
/// </summary>
public class DragHandleConnection
{
public void AddTarget(DependencyProperty p, DependencyObject o,
SourceAxes s)
{
_targets.Add( new DragHandleTarget(p, o, s) );
}
/// <summary>
/// The CoercePointCallback will be invoked when the DragHandle
/// position changes, before the position is sent to clients.
/// </summary>
public CoercePointCallback CoercePoint;
/// <summary>
/// Gets the list of DragHandleTargets associated with this connection
/// </summary>
public List<DragHandleTarget> Targets
{
get { return _targets; }
}
/// <summary>
/// Implements the Targets property
/// </summary>
List<DragHandleTarget> _targets = new List<DragHandleTarget>();
}
/// <summary>
/// DragHandleConnector is the overall container for a set of
/// connections attached to a specific DragHandler
/// </summary>
public class DragHandleConnector
{
/// <summary>
/// Create a DragHandleConnector attached to the specified
/// DragHandle
/// </summary>
/// <param name="dh">An instance of DragHandle</param>
public DragHandleConnector( DragHandle dh )
{
SetHandle( dh );
}
/// <summary>
/// Disconnects the connection from a DragHandle by unwiring its
/// event handler. This should when the connection is no
/// longer needed.
/// </summary>
public void Disconnect()
{
if (null != _dh)
_dh.Drag -= new EventHandler<DragHandleEventArgs>(DragHandle_Drag);
}
/// <summary>
/// Gets and sets the DragHandle associated with this connector
/// </summary>
public DragHandle Handle
{
get { return _dh; }
set { SetHandle(value); }
}
/// <summary>
/// Gets the list of DragHandleConnections for this connector
/// </summary>
public List<DragHandleConnection> Connections
{
get { return _connections; }
}
/// <summary>
/// Used internally to connect a drag handle, while making sure that
/// the previous handle, if any, is disconnected.
/// </summary>
/// <param name="dh"></param>
private void SetHandle( DragHandle dh )
{
Disconnect();
_dh = dh;
_dh.Drag += new EventHandler<DragHandleEventArgs>(DragHandle_Drag);
}
/// <summary>
/// Handles the Drag event for connected DragHandles
/// </summary>
/// <param name="sender">a DragHandle</param>
/// <param name="e">event arguments</param>
private void DragHandle_Drag( object sender, DragHandleEventArgs e )
{
for( int i = 0; i < _connections.Count; i++ )
{
Point p;
DragHandleConnection d = _connections[i];
if (null != d.CoercePoint)
p = d.CoercePoint(e.Position);
else
p = e.Position;
for ( int j = 0; j < d.Targets.Count; j++ )
{
DragHandleTarget t = d.Targets[j];
switch ( t.Axes )
{
case SourceAxes.Both:
t.Owner.SetValue(t.Property, p);
break;
case SourceAxes.X:
t.Owner.SetValue(t.Property, p.X);
break;
case SourceAxes.Y:
t.Owner.SetValue(t.Property, p.Y);
break;
}
}
}
}
private DragHandle _dh;
private List<DragHandleConnection> _connections =
new List<DragHandleConnection>();
}
}