Skip to content

Adaptable Controls

Gary edited this page Aug 27, 2014 · 1 revision

The AdaptableControl class provides an adaptable control, which is a control decorated with adapters. An adaptable control can be converted into any of its adapters by using the IAdaptable.As method. Such a control is very versatile.

The AdaptableControl class provides the Adapt() method to adapt the control to all the specified adapters:

public void Adapt(params IControlAdapter[] adapters);

Each adapter provided in the array is an object of the ControlAdapter class, implementing IControlAdapter. This interface consists of methods to bind and unbind the adapter to or from its underlying control. The Bind() method for each adapter is called in the order that the adapters were listed in the Adapt() method. By convention, the bottom-most layer should appear first in the AdaptableControl's Adapt() method, and so the Paint event should be subscribed to in Bind().

For more information on adaptation, see Adaptation in ATF.

This example from the Editor class in the ATF FSM Editor Sample illustrates setting up an AdaptableControl. The steps in this process are:

  1. Create the AdaptableControl. This example creates an object of the class D2dAdaptableControl, which derives from AdaptableControl.
  2. Invoke SuspendLayout() on the new AdaptableControl to suspend layout operations while the control is being configured.
  3. Set any AdaptableControl properties desired, such as BackColor.
  4. Create the ControlAdapter objects. All of these objects, such as ViewingAdapter, eventually derive from ControlAdapter. These adapters all perform different tasks, as noted in the comments. For instance, ViewingAdapter implements IViewingContext for framing or ensuring that items are visible. Configure these adapters as needed. For instance, HoverAdapter needs to subscribe to some events.
  5. Call AdaptableControl.Adapt() with an array of the ControlAdapter objects. You can use as many ControlAdapter objects as you want.
  6. Invoke ResumeLayout() on the new AdaptableControl to resume layout operations.
  7. Perform any other initialization needed, such as setting up contexts, documents, initializing DOM adapters, and so on.
  8. Register the AdaptableControl by invoking RegisterControl() on the ControlHostService instance.
// set up the AdaptableControl for editing FSMs
var control = new D2dAdaptableControl();
control.SuspendLayout();

control.BackColor = SystemColors.ControlLight;
control.AllowDrop = true;

var transformAdapter = new TransformAdapter(); // required by several of the other adapters
transformAdapter.UniformScale = true;
transformAdapter.MinScale = new PointF(0.25f, 0.25f);
transformAdapter.MaxScale = new PointF(4, 4);

var viewingAdapter = new ViewingAdapter(transformAdapter); // implements IViewingContext for framing or ensuring that items are visible

var canvasAdapter = new CanvasAdapter(); // implements a bounded canvas to limit scrolling

var autoTranslateAdapter = // implements auto translate when the user drags out of control's client area
    new AutoTranslateAdapter(transformAdapter);
var mouseTransformManipulator = // implements mouse drag translate and scale
    new MouseTransformManipulator(transformAdapter);
var mouseWheelManipulator = // implements mouse wheel scale
    new MouseWheelManipulator(transformAdapter);
var scrollbarAdapter = // adds scroll bars to control, driven by canvas and transform
    new ScrollbarAdapter(transformAdapter, canvasAdapter);

var hoverAdapter = new HoverAdapter(); // add hover events over pickable items
hoverAdapter.HoverStarted += control_HoverStarted;
hoverAdapter.HoverStopped += control_HoverStopped;

var annotationAdaptor = new D2dAnnotationAdapter(m_theme); // display annotations under diagram

var fsmAdapter = // adapt control to allow binding to graph data
    new D2dGraphAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, transformAdapter);

var fsmStateEditAdapter = // adapt control to allow state editing
    new D2dGraphNodeEditAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, fsmAdapter, transformAdapter);

var fsmTransitionEditAdapter = // adapt control to allow transition
    new D2dGraphEdgeEditAdapter<State, Transition, NumberedRoute>(m_fsmRenderer, fsmAdapter, transformAdapter);

var mouseLayoutManipulator = new MouseLayoutManipulator(transformAdapter);

// apply adapters to control; ordering is from back to front, that is, the first adapter
//  will be conceptually underneath all the others. Mouse and keyboard events are fed to
//  the adapters in the reverse order, so it all makes sense to the user.
control.Adapt(
    hoverAdapter,
    scrollbarAdapter,
    autoTranslateAdapter,
    new RectangleDragSelector(),
    transformAdapter,
    viewingAdapter,
    canvasAdapter,
    mouseTransformManipulator,
    mouseWheelManipulator,
    new KeyboardGraphNavigator<State, Transition, NumberedRoute>(),
    //new GridAdapter(),
    annotationAdaptor,
    fsmAdapter,
    fsmStateEditAdapter,
    fsmTransitionEditAdapter,
    new LabelEditAdapter(),
    new SelectionAdapter(),
    mouseLayoutManipulator,
    new DragDropAdapter(m_statusService),
    new ContextMenuAdapter(m_commandService, m_contextMenuCommandProviders)
    );

control.ResumeLayout();

// associate the control with the viewing context; other adapters use this
//  adapter for viewing, layout and calculating bounds.
ViewingContext viewingContext = node.Cast<ViewingContext>();
viewingContext.Control = control;

// set document URI
document = node.As<Document>();
ControlInfo controlInfo = new ControlInfo(fileName, filePath, StandardControlGroup.Center);

//Set IsDocument to true to prevent exception in command service if two files with the
//  same name, but in different directories, are opened.
controlInfo.IsDocument = true;

document.ControlInfo = controlInfo;
document.Uri = uri;

// now that the data is complete, initialize the rest of the extensions to the Dom data;
//  this is needed for adapters such as validators, which may not be referenced anywhere
//  but still need to be initialized.
node.InitializeExtensions();

// set control's context to main editing context
EditingContext editingContext = node.Cast<EditingContext>();
control.Context = editingContext;

// show the FSM control
m_controlHostService.RegisterControl(control, controlInfo, this);

Topics in this section

Clone this wiki locally