Representing elements of diagrams

  • XCaseCanvas
  • IModelRepresentant, Registrations
  • Binding, ViewPropertyBinding, ModelPropertyBinding

When diagram elements are created in the UML model, event mechanism notifies View about the changes. It is up to the View to reflect the changes in user interface, show the elements on the diagram.

XCaseCanvas

XCaseCanvas is the class that represent one diagram in user interface. When new diagram is opened, XCaseCanvas is an empty panel. It listens to the events in Diagram class (ElementAdded and ElementRemoved). When an element is added XCaseCanvas creates its representation.

Representing elements

Part of XCaseCanvas’ initialization is initialization of the ElementRepresentations. This object creates visual representation of each element that is added into the diagram. Visual representations of elements must implement IModelElementRepresentant interface. Since View uses WPF for drawing, visual representation of an element is usually composed of one or more WPF controls (for example: representation of an Association is made of points of the association, line that goes through the points and set of labels). The WPF controls that the representation composes of should be added to XCaseCanvas in the implementation of method InitializeRepresentant. The same controls that were added in InitializeRepresentant should be removed in DeleteFromCanvas method.

InitializeRepresentant receives reference of XCaseCanvas, the element that should be represented and its ViewHelper (see ViewHelper section for more information about ViewHelpers).

Binding Model properties to View

Very often it is desired to update some properties of model element representant when properties of represented element change (e.g. when Class’ Name property is changed via RenameElementCommand, XCaseClass’ Name property should be updated to contain the same value). Copying value of model element property into representant property can be easily achieved via set of metadata attributes XCase supports and thanks to property change notifications coming from the model elements (model elements implement INotifyPropertyChange, collection of elements implement INotifyCollectionChange).

Binding infrastructure expects that each model element representant will have two properties – one referring to represented model element and one to the element’s ViewHelper. Declarative attribute markup is used to declare these two properties

This section deserves an example - Comment example was chosen because it is simple, but can demonstrate most of the binding features.

This is part of XCaseCommentary code declaring ViewHelper and model element references:

public class XCaseCommentary: IModelElementRepresentant
{
	[ModelElement]
	public Comment ModelComment { get… }

	[ViewHelperElement]
	public CommentViewHelper ViewHelper { get… }
}

ModelElement attribute is used in ModelComment property declaration – this property will be used by the binding infrastructure as a source of model binding. ViewHelperElement property is used to declare source of view binding in a similar way.

Another pair of attribute is used to declare binding between pair of properties itself:

[ModelPropertyMapping("Body")]
public string CommentText …

The declaration above says that each update of ModelComment.Body will update property CommentText.

ViewPropertyMapping attribute can be declared in the same way as ModelPropertyMapping attribute.

There is also an equivalent way to define the mappings – use the attributes on classes instead of properties, following declaration is equivalent to the declaration above:

[ModelPropertyMapping("Body", "CommentText")]
public class XCaseCommentary 
{
	…
	public string CommentText …
}

This second way of declaring the mappings is useful when a property is declared in a base class but mapping is defined in derived class (thus there is no place to declare an attribute in the derived class without overriding the property). For example this is how X and Y properties of base class DragThumb (that is a base class to ConnectableDragThumb) are bound to ViewHelper properties, X and Y are not overridden in XCaseCommentary:

[ViewHelperPropertyMapping("X", "X")]
[ViewHelperPropertyMapping("Y", "Y")]
public class XCaseCommentary : ConnectableDragThumb, IModelElementRepresentant

This was the declarative part. The process of binding on a certain object must be explicitly started at runtime by calling method StartBindings (extension method of IBindable interface – it doesn’t have to be implemented by model element representants, only XCase.UMLController interface must be imported.

CloseBindings method suspends binding for the object.

Good time to call StartBindings is at the end of InitializeRepresentant method (from IModelRepresentant), good time to call CloseBindings is at the end of DeleteFromCanvas method (from IDeletable).

Note: C# compiler requires this qualifier when calling StartBindings and CloseBindings. These methods must be called using this qualifier: this.StartBindings() resp. this.CloseBindings(). Both methods also provide overrides that start/closes only model bindings or only view bindings.

Last edited Oct 8, 2008 at 10:13 AM by Trupik, version 4

Comments

No comments yet.