-
Notifications
You must be signed in to change notification settings - Fork 263
Simple DOM Editor Programming Discussion
The ATF Simple DOM Editor Sample shows defining a data model in an XML Schema, editing data, and saving the edited data in an XML file. Application data is displayed in two ListView
controls, and its properties can be examined in two property editors.
This application's data consist of sequences of events, which can contain resources. The sequence of events is displayed in the main ListView
control, and the resources of the selected event are listed in the Resources ListView
control.
Note that "event" in this context means application data, not an event that is processed by an event handler. Both meanings of the term are used in this discussion, and the meaning of "event" should be clear from the context.
This sample is especially interesting, because this Programmer's Guide describes converting this particular sample into another ATF application. To walk through this process, see Creating an Application from an ATF Sample.
SimpleDOMEditor uses an XML Schema to define its data model of sequences of events with resources. Its schema loader also defines DOM adapters, palette items, and property descriptors that determine which properties appear in the property editors.
The application's PaletteClient
along with ATF's PaletteService
creates a palette of events and resource items.
SimpleDOMEditor provides the DOM adapters Event
, EventSequence
, and Resource
for their corresponding types to provide properties that access information in a DomNode
of that type.
SimpleDOMEditor relies heavily on contexts. EventContext
handles resources belonging to the selected event and manages the Resources window ListView
editing. This context implements a host of interfaces to handle displaying items, selection, and editing. EventSequenceContext
does a similar job for a sequence of events in the main window's ListView
, including handling subselection of a properties of an event.
EventSequenceDocument
extends DomDocument
, which implements IDocument
. The Editor
component is its document client, handling closing and saving documents.
The EventListEditor
and ResourceListEditor
components edit event sequences and their associated resources in their ListView
s, handling drag and drop as well as copy, paste, and delete.
This sample also shows how to search DomNode
s, using the components DomNodeNameSearchService
and DomNodePropertySearchService
. Searching also uses DomNodeQueryable
, which is defined as a DOM adapter for the root type in SchemaLoader
, so any node can be searched.
SimpleDOMEditor's initialization is typical for a WinForms application, as described in WinForms Application in the ATF Application Basics and Services section. Its MEF TypeCatalog
contains components in the application shell framework, such as SettingsService
, StatusService
, CommandService
, and ControlHostService
. It uses components to handle documents: DocumentRegistry
, AutoDocumentService
, RecentDocumentCommands
, StandardFileCommands
, StandardFileExitCommand
, MainWindowTitleService
, and TabbedControlSelector
. Editing and context management are handled by ContextRegistry
, StandardEditCommands
, StandardEditHistoryCommands
, and StandardSelectionCommands
. How these common components function is discussed elsewhere in this Guide, such as Documents in ATF and ATF Contexts.
The PropertyEditor
, GridPropertyEditor
, and PropertyEditingCommands
components handle property editing. These are well integrated with the ATF DOM, so the application only needs to include these components to be able to edit properties of the application's data. For details on property editing, see Property Editing in ATF.
SimpleDOMEditor adds a few custom components of its own:
-
PaletteClient
: populate the palette with items described by DOM types, with help from the ATF componentPaletteService
. For details, see Using a Palette. -
DomNodeNameSearchService
andDomNodePropertySearchService
: provide a GUI for searching and replacement ofDomNode
names on the currently active document. See Node Searching. -
Editor
: create and save event sequence documents. See Document Handling. -
SchemaLoader
: load the XML Schema for the data model as well as define property descriptors and palette items. See Data Model. -
EventListEditor
: track event sequence contexts and controls that display event sequences. See Working With Contexts. -
ResourceListEditor
: display and edit resources that belong to the most recently selected event. See ResourceListEditor Component.
This application creates and edits event sequences. An event has attributes, such as duration, and can contain one or more resources, such as animations. The sample defines its data model in the XML Schema Definition (XSD) language in the type definition file eventSequence.xsd
. This figure shows the Visual Studio XML Schema Explorer view of the sample's data definition:
This tree view shows that an "Event", eventType
, contains a "Resource", resourceType
, and has "name", "time", and "duration" attributes. The XML Schema for this type definition shows a different view of the same thing:
<!--Event, with name, start time, duration and a list of resources-->
<xs:complexType name ="eventType">
<xs:sequence>
<xs:element name="resource" type="resourceType" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="time" type="xs:integer"/>
<xs:attribute name="duration" type="xs:integer"/>
</xs:complexType>
The data model has a "Resource" type, and the types "Animation" and "Geometry" are based on "Resource". "Resource" types have the attributes "name", "size", and "compressed".
An event sequence is simply a sequence of any number of events, as this type definition shows:
<!--Event sequence, a sequence of events-->
<xs:complexType name ="eventSequenceType">
<xs:sequence>
<xs:element name="event" type="eventType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
Note this definition for the root element:
<!--Declare the root element of the document-->
<xs:element name="eventSequence" type="eventSequenceType"/>
The root element is of "EventSequence" type, because a document contains one event sequence. This is very important, because this type has several DOM adapters defined for it, which can apply to the entire document.
The ATF DomGen utility generated a Schema
class file from the type definition file. The file GenSchemaDef.bat
contains commands for DomGen.
Schema
contains subclasses for all the data types and fields for the attributes that are of the appropriate ATF DOM metadata classes.
For example, the "Resource" type has three AttributeInfo
fields for its "name", "size", and "compressed" attributes:
public static class resourceType
{
public static DomNodeType Type;
public static AttributeInfo nameAttribute;
public static AttributeInfo sizeAttribute;
public static AttributeInfo compressedAttribute;
}
The "Event" type also has AttributeInfo
fields for its attributes, plus a ChildInfo
field for any resources contained in the object:
public static class eventType
{
public static DomNodeType Type;
public static AttributeInfo nameAttribute;
public static AttributeInfo timeAttribute;
public static AttributeInfo durationAttribute;
public static ChildInfo resourceChild;
}
Even though an event may contain any number of resources, it needs only one ChildInfo
object, because in the ATF DOM, a node can have either a single child or a single list of children in the DOM node tree.
The SchemaLoader
component loads the XML schema and does any other initialization required for the data model. It derives from XmlSchemaTypeLoader
, which performs a substantial part of the schema loading process.
Its constructor, which is automatically called during MEF initialization when the component object is created, resolves the type definition file address and loads the file:
public SchemaLoader()
{
// set resolver to locate embedded .xsd file
SchemaResolver = new ResourceStreamResolver(Assembly.GetExecutingAssembly(), "SimpleDomEditorSample/schemas");
Load("eventSequence.xsd");
}
SchemaLoader
constructors nearly always take this form. Other standard items are the NameSpace
and TypeCollection
properties:
public string NameSpace
{
get { return m_namespace; }
}
private string m_namespace;
...
public XmlSchemaTypeCollection TypeCollection
{
get { return m_typeCollection; }
}
private XmlSchemaTypeCollection m_typeCollection;
The other work to do is to define the method OnSchemaSetLoaded()
, which is called after the schema set has been loaded and the DomNodeType
objects have been created. This method accomplishes several things, described in the following sections.
The schema loader calls Schema.Initialize()
to initialize the Schema
class. This method was also created by DomGen when it generated the rest of the metadata classes.
The loader defines DOM extensions for data types, so that methods in the various DOM adapters are called appropriately:
Schema.eventSequenceType.Type.Define(new ExtensionInfo<EventSequenceDocument>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<EventSequenceContext>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<MultipleHistoryContext>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<EventSequence>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<ReferenceValidator>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<UniqueIdValidator>());
Schema.eventSequenceType.Type.Define(new ExtensionInfo<DomNodeQueryable>());
Schema.eventType.Type.Define(new ExtensionInfo<Event>());
Schema.eventType.Type.Define(new ExtensionInfo<EventContext>());
Schema.resourceType.Type.Define(new ExtensionInfo<Resource>());
Note that the types used here are the ones defined in the Schema
class.
The first group's definitions all apply to Schema.eventSequenceType
, which is the type of the document's root. These DOM adapters thus apply to the entire document and accomplish a variety of purposes. A document describes a single sequence of events, so its DomNode
tree has only one node of type "EventSequence", the tree root DomNode
. This root node can be adapted to all of the adapters listed above. For instance, it's useful at times to treat the document as a EventSequenceContext
. For more details, see Working With Contexts.
The Schema.eventType
and Schema.resourceType
types also have DOM adapters. For more information on these adapters, see DOM Adapters.
The schema loader enables metadata driven property editing for events and resources by creating an AdapterCreator
:
AdapterCreator<CustomTypeDescriptorNodeAdapter> creator =
new AdapterCreator<CustomTypeDescriptorNodeAdapter>();
Schema.eventType.Type.AddAdapterCreator(creator);
Schema.resourceType.Type.AddAdapterCreator(creator);
If this were not done, property editors would not show properties from the property descriptors, defined later on. For more details, see Metadata Driven Property Editing.
This step adds tag information to the type that is used later to add these types to the palette: "Event", "Animation", and "Geometry". The palette item information is encapsulated in a NodeTypePaletteItem
object, a container class:
Schema.eventType.Type.SetTag(
new NodeTypePaletteItem(
Schema.eventType.Type,
Localizer.Localize("Event"),
Localizer.Localize("Event in a sequence"),
Resources.EventImage));
The NodeTypePaletteItem
contains all the information needed to display and use the palette item: its type, descriptive text, and an icon image to appear on the palette and in the ListView
controls.
For further details on how this sets up the palette, see Using a Palette.
Property descriptors for types specify the data that shows up in property editors for the types. For details on how this works, see Property Editing in ATF and Property Descriptors in particular.
This NamedMetadata.SetTag()
call's first parameter creates a PropertyDescriptorCollection
containing an AttributePropertyDescriptor
for each attribute of an "Event" type. This information is required for each attribute to appear in a property editor when an event is selected in the main ListView
. The AdapterCreator
must also be set up, as described previously in Metadata Driven Property Editing.
Schema.eventType.Type.SetTag(
new PropertyDescriptorCollection(
new PropertyDescriptor[] {
new AttributePropertyDescriptor(
Localizer.Localize("Name"),
Schema.eventType.nameAttribute,
null,
Localizer.Localize("Event name"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Time"),
Schema.eventType.timeAttribute,
null,
Localizer.Localize("Event starting time"),
false),
new AttributePropertyDescriptor(
Localizer.Localize("Duration"),
Schema.eventType.durationAttribute,
null,
Localizer.Localize("Event duration"),
false),
}));
SimpleDOMEditor uses the ATF PaletteService
component, which manages a palette of objects that can be dragged onto other controls. SimpleDOMEditor allows dragging palette items onto the two ListView
controls: the main ListView
for event sequences and the Resources ListView
for resources of the selected event. PaletteService
's constructor creates a System.Windows.Forms.UserControl
for the palette, configures it, and registers it with the ControlHostService
component, placing the control on the left side of the main window.
SimpleDOMEditor adds its own PaletteClient
component that imports IPaletteService
, which is exported by ATF's PaletteService
component. The IInitializable.Initialize()
method for the PaletteClient
component adds items to the palette:
void IInitializable.Initialize()
{
string category = "Events and Resources";
m_paletteService.AddItem(Schema.eventType.Type, category, this);
foreach (DomNodeType resourceType in m_schemaLoader.GetNodeTypes(Schema.resourceType.Type))
{
NodeTypePaletteItem paletteItem = resourceType.GetTag<NodeTypePaletteItem>();
if (paletteItem != null)
m_paletteService.AddItem(resourceType, category, this);
}
}
This method adds items to the palette with the IPaletteService.AddItem()
method, defined as:
void AddItem(object item, string categoryName, IPaletteClient client);
In the first call to AddItem()
, the type for an event is added, Schema.eventType.Type
, in the "Events and Resources" category.
The foreach
loop iterates through all the types for the "Resource" type, Schema.resourceType.Type
. The types "Animation" and "Geometry" are both based on the "Resource" type. For each of these "Resource" types, the loop checks that it can get a NodeTypePaletteItem
for the type:
NodeTypePaletteItem paletteItem = resourceType.GetTag<NodeTypePaletteItem>();
Recall that in the SchemaLoader
class, this kind of initialization occurs to add information for each "Resource" type for the palette:
Schema.animationResourceType.Type.SetTag(
new NodeTypePaletteItem(
Schema.animationResourceType.Type,
Localizer.Localize("Animation"),
Localizer.Localize("Animation resource"),
Resources.AnimationImage));
This call to GetTag()
above simply retrieves the above NodeTypePaletteItem
information, if present. After it verifies that the type has an associated NodeTypePaletteItem
, Initialize()
adds the type to the palette.
Looping in this way guarantees that all resource types are added to the palette and makes adding new resource types to the palette later easier.
The IPaletteClient.GetInfo()
method gets display information for the item. It retrieves the data from the NodeTypePaletteItem
that was set in SchemaLoader
:
void IPaletteClient.GetInfo(object item, ItemInfo info)
{
DomNodeType nodeType = (DomNodeType)item;
NodeTypePaletteItem paletteItem = nodeType.GetTag<NodeTypePaletteItem>();
if (paletteItem != null)
{
info.Label = paletteItem.Name;
info.Description = paletteItem.Description;
info.ImageIndex = info.GetImageList().Images.IndexOfKey(paletteItem.ImageName);
}
}
This method first casts the item as a DomNodeType
and creates a DomNode
of that type. The item
parameter in Convert()
is an item in the palette. And the items that were added to the palette are types, as in this line:
m_paletteService.AddItem(Schema.eventType.Type, category, this);
These palette items, like Schema.eventType
, as defined in the Schema
class:
public static class eventType
{
public static DomNodeType Type;
public static AttributeInfo nameAttribute;
public static AttributeInfo timeAttribute;
public static AttributeInfo durationAttribute;
public static ChildInfo resourceChild;
}
So these items are already a DomNodeType
, and the cast succeeds.
GetInfo()
then simply sets the ItemInfo
properties from the fields of the type's NodeTypePaletteItem
object, which it obtains by calling GetTag()
.
IPaletteClient.Convert()
takes a palette item and returns an object that can be inserted into an IInstancingContext
— a DomNode
in this case:
object IPaletteClient.Convert(object item)
{
DomNodeType nodeType = (DomNodeType)item;
DomNode node = new DomNode(nodeType);
NodeTypePaletteItem paletteItem = nodeType.GetTag<NodeTypePaletteItem>();
if (paletteItem != null)
{
if (nodeType.IdAttribute != null)
node.SetAttribute(nodeType.IdAttribute, paletteItem.Name); // unique id, for referencing
if (nodeType == Schema.eventType.Type)
node.SetAttribute(Schema.eventType.nameAttribute, paletteItem.Name);
else if (Schema.resourceType.Type.IsAssignableFrom(nodeType))
node.SetAttribute(Schema.resourceType.nameAttribute, paletteItem.Name);
}
return node;
}
This method first casts the item as a DomNodeType
and creates a DomNode
of that type. The item
parameter in Convert()
is a selected item in the palette.
Next, the method GetTag()
is used once again to retrieve a NodeTypePaletteItem
containing palette item information.
The rest of the code sets attributes of the DomNode
with the DomNode.SetAttribute()
method:
public void SetAttribute(AttributeInfo attributeInfo, object value);
Both the ID and Name attributes are set. The type of item is checked, so that the proper nameAttribute
can be set.
DOM adapters allow a DomNode
to be dynamically cast to another object type or interface. SimpleDOMEditor provides the DOM adapters Event
, EventSequence
, and Resource
for their corresponding types. All these adapters do is provide properties that access information in a DomNode
. For instance, Event
has a Name
property:
/// Gets or sets name associated with event, such as a label
public string Name
{
get { return GetAttribute<string>(Schema.eventType.nameAttribute); }
set { SetAttribute(Schema.eventType.nameAttribute, value); }
}
The DomNodeAdapter.GetAttribute()
method gets the value of a specified attribute, Schema.eventType.nameAttribute
, defined in the Schema
class as
public static AttributeInfo nameAttribute;
Most of the DOM adapter properties simply access attribute values of the type, but the EventSequence
DOM adapter's Events
property gets all the events in an event sequence:
/// Gets list of Events in sequence
public IList<Event> Events
{
get { return GetChildList<Event>(Schema.eventSequenceType.eventChild); }
}
Note that the returned property value is a IList<Event>
, that is, a list of the DOM adapter Event
objects associated with an event sequence DOM adapter EventSequence
.
The DOM adapters in this application provide a simple way to get properties for the event, event sequence, and resource objects, all embodied in DomNode
objects.
SimpleDOMEditor relies heavily on contexts. A context provides services for operations in certain situations, hence the name context. ATF provides quite a few interfaces and classes for different types of contexts, and this sample uses several. For information about contexts in general, see ATF Contexts.
This section illustrates how contexts control and facilitate editing operations in the main and Resources ListView
controls.
EventContext
handles resources belonging to the selected event and manages the Resources ListView
's editing. This class adapts the application data to a list and uses contexts to enable data editing as well as undoing and redoing data changes. EventContext
implements interfaces to do much of its work.
EventContext
has this derivation ancestry: EditingContext
, HistoryContext
, TransactionContext
, and finally DomNodeAdapter
, so all these context classes are DOM adapters. EditingContext
is a history context with a selection, providing a basic self-contained editing context. Several samples, such as ATF Fsm Editor Sample and ATF State Chart Editor Sample have context classes that extend EditingContext
. For more information about this context, see General Purpose EditingContext Class.
As its declaration shows, EventContext
also implements several context and other interfaces:
public class EventContext : EditingContext,
IListView,
IItemView,
IObservableContext,
IInstancingContext,
IEnumerableContext
EventContext
's ancestor classes also implement some useful interfaces, such as IHistoryContext
and ITransactionContext
, which allow changes in the context, such as deleting resources in an event, to be undone and redone.
As a DOM adapter, EventContext
's OnNodeSet()
method subscribes to several events for a DomNode
, such as ChildInserted
:
DomNode.ChildInserted += new EventHandler<ChildEventArgs>(DomNode_ChildInserted);
...
private void DomNode_ChildInserted(object sender, ChildEventArgs e)
{
Resource resource = e.Child.As<Resource>();
if (resource != null)
{
ItemInserted.Raise(this, new ItemInsertedEventArgs<object>(e.Index, resource));
}
}
If this handler can adapt the DomNode
to the Resource
DOM adapter, it raises the ItemInserted
event, which is defined in the IObservableContext
interface.
The other event handlers, subscribed to in OnNodeSet()
, deal with Resource
objects in a similar way.
IListView
offers a couple of properties with information about the Resources ListView
. Items
gets the list of resources and Columns
provides the column headers.
Note that a DomNode
for an Event
can have a list of "Resource" DomNode
children that belong to the Event
. Therefore, the Items
property gets a list of children:
public IEnumerable<object> Items
{
get { return GetChildList<object>(Schema.eventType.resourceChild); }
}
This property value is also returned by the IEnumerableContext.Items
property.
ColumnNames
simply returns a list of name strings for the columns that are displayed in the ListView
:
public string[] ColumnNames
{
get { return new string[] { Localizer.Localize("Name"), Localizer.Localize("Size") }; }
}
IItemView
's GetInfo()
method complements IListView
by setting an ItemInfo
with information for each column in the ListView
:
public void GetInfo(object item, ItemInfo info)
{
Resource resource = Adapters.As<Resource>(item);
info.Label = resource.Name;
string type = null;
if (resource.DomNode.Type == Schema.animationResourceType.Type)
type = Resources.AnimationImage;
else if (resource.DomNode.Type == Schema.geometryResourceType.Type)
type = Resources.GeometryImage;
info.ImageIndex = info.GetImageList().Images.IndexOfKey(type);
info.Properties = new object[] { resource.Size };
}
The resource DomNode
specified in item
is adapted to the Resource
DOM adapter. ItemInfo.Label
is set to the Name
property of the Resource
. The resource type is checked to decide which icon to associate with the item. The icon and name go in the "Name" column of the ListView
. The "Size" column's value comes from the ItemInfo.Properties
value, constructed from the property Resource.Size
.
IInstancingContext
handles instancing in the Resources ListView
, that is, working with resource instances in this control, which can be edited using menu items and by drag and drop. You insert resources in the Resources ListView
for an event by dragging and dropping a resource from the palette onto the Resources ListView
. Such drag and drop events are also handled using the IInstancingContext
interface. For a description of how this is done, see the section Drag and Drop and Instancing in the Instancing In ATF topic.
The IInstancingContext
interface provides methods to check whether items can be copied, inserted (pasted), or deleted, and performs these actions, too.
Here are the copy related methods:
public bool CanCopy()
{
return Selection.Count > 0;
}
...
public object Copy()
{
IEnumerable<DomNode> resources = Selection.AsIEnumerable<DomNode>();
List<object> copies = new List<object>(DomNode.Copy(resources));
return new DataObject(copies.ToArray());
}
Selection
is defined in the EditingContext
class and is an AdaptableSelection
representing a collection of selected objects; this class handles basic selection mechanics. CanCopy()
uses Selection
to simply verify that there is at least one selected item. Copy()
adapts the selection to a collection of DomNode
s, copies them as a list of object
s, and then constructs a System.Windows.Forms.DataObject
from the copy, which can be placed on the Windows® clipboard. The StandardEditCommands
component actually calls Copy()
and puts the copied data onto the clipboard.
CanInsert()
and Insert()
do the following:
public bool CanInsert(object insertingObject)
{
IDataObject dataObject = (IDataObject)insertingObject;
object[] items = dataObject.GetData(typeof(object[])) as object[];
if (items == null)
return false;
foreach (object item in items)
if (!Adapters.Is<Resource>(item))
return false;
return true;
}
...
public void Insert(object insertingObject)
{
IDataObject dataObject = (IDataObject)insertingObject;
object[] items = dataObject.GetData(typeof(object[])) as object[];
if (items == null)
return;
DomNode[] itemCopies = DomNode.Copy(Adapters.AsIEnumerable<DomNode>(items));
IList<Resource> resources = this.Cast<Event>().Resources;
foreach (Resource resource in Adapters.AsIEnumerable<Resource>(itemCopies))
resources.Add(resource);
Selection.SetRange(itemCopies);
}
The first part of both methods is identical, simply verifying that there's data to insert.
StandardEditCommands
calls CanInsert()
to determine whether the Insert menu item is enabled or not. CanInsert()
casts the inserted data as a IDataObject
and then casts it to an array of selected object
s, each of which is a DomNode
of type "Resource". The second part of CanInsert()
checks whether all the selected items can be adapted as Resource
objects. If so, the method returns true, and false otherwise.
For the insert operation, StandardEditCommands
gets the clipboard data and calls Insert()
to insert this data. Insert()
casts the inserted data as a IDataObject
and then casts it to an array of selected object
s, just as for CanInsert()
. These object
s are adapted to DomNode
s and then copied.
In this method, this
represents an EventContext
object,which is an adapted DomNode
of type "Event" representing a selected event in the main ListView
. Both EventContext
and Event
are DOM adapters for the "Event" type, as shown in these lines from SchemaLoader
where DOM adapters are defined:
Schema.eventType.Type.Define(new ExtensionInfo<Event>());
Schema.eventType.Type.Define(new ExtensionInfo<EventContext>());
Because Event
is a DOM adapter for a DomNode
of type "Event", this DomNode
can be adapted to an Event
object, and its list of resources can be obtained from the Resources
property of the Event
DOM adapter:
IList<Resource> resources = this.Cast<Event>().Resources;
Finally, each inserted DomNode
is adapted to a Resource
object and added to the list of resources for the selected Event
in the main ListView
.
The deletion operations are simpler:
public bool CanDelete()
{
return Selection.Count > 0;
}
...
public void Delete()
{
foreach (DomNode node in Selection.AsIEnumerable<DomNode>())
node.RemoveFromParent();
Selection.Clear();
}
CanDelete()
is identical to CanCopy()
, simply verifying that there's something selected to delete.
Delete()
iterates all selected items' underlying DomNode
s and removes them from their parents with DomNode.RemoveFromParent()
, effectively removing them from the application data. It also clears the selection using the Selection.Clear()
method.
EventSequenceContext
handles a sequence of events in the main ListView
, managing editing this list.
EventSequenceContext
has many similarities to EventContext
, including its derivation ancestry from EditingContext
. One of the differences is that EventSequenceContext
's constructor creates and configures the ListView
instance used to display events. It also creates a GenericSelectionContext
as a subselection context.
EventSequenceContext
implements all the interfaces that EventContext
does. Their implementations are almost identical, but Resource
objects are replaced by Event
objects in EventSequenceContext
. The IInstancingContext
implementations look identical except for that substitution, for example.
The IListView
implementation merely has the obvious differences from EventContext
. The Items
property returns a child list of Event
objects, rather than Resource
objects. ColumnNames
returns the list of headings seen over the main ListView
columns.
public IEnumerable<object> Items
{
get { return GetChildList<object>(Schema.eventSequenceType.eventChild); }
}
...
public string[] ColumnNames
{
get { return new string[] { Localizer.Localize("Name"), Localizer.Localize("Duration") }; }
}
ISubSelectionContext
is implemented for node search to show which attribute was found in a list of search hits when a hit list entry is selected. The found attribute in the selected node is highlighted in the property editor, which constitutes the subselection. For details, see Node Searching.
EventSequenceContext
uses GenericSelectionContext
for a subselection context:
m_subSelectionContext = new GenericSelectionContext();
EventSequenceContext
implements the property ISubSelectionContext.SubSelectionContext
, which returns an ISelectionContext
:
public ISelectionContext SubSelectionContext
{
get { return m_subSelectionContext; }
}
GenericSelectionContext
is a straightforward implementation of ISelectionContext
. Its constructor creates a Selection
object and subscribes to a Changed
event on it:
public GenericSelectionContext()
{
m_selection = new Selection<object>();
m_selection.Changed += new EventHandler(selection_Changed);
// suppress compiler warning
if (SelectionChanging == null) return;
}
The Changed
event is raised when a subselection occurs. For details on how this occurs, see Node Searching.
The ISelectionContext
implementation simply makes use the Selection
object, as in GetSelection<T>()
and LastSelected
:
public IEnumerable<T> GetSelection<T>()
where T : class
{
return m_selection.AsIEnumerable<T>();
}
...
public object LastSelected
{
get { return m_selection.LastSelected; }
}
Document handling applications typically implement both IDocument
for a document object and IDocumentClient
for the document client.
EventSequenceDocument
extends DomDocument
, which implements IDocument
.
The DomDocument
class provides the basics of a document: IsReadOnly
and Dirty
properties, a DirtyChanged
event, and the OnDirtyChanged()
and OnReloaded
event handlers. DomDocument
extends DomResource
and implements IResource
to provide the resource properties Type
and Uri
to describe a document's type and location.
EventSequenceDocument
itself implements overrides for the property Type
and the methods OnUriChanged()
and OnDirtyChanged()
for application-specific behavior. These latter event handlers simply execute the base methods, as well as update ControlInfo
for the ListView
displaying the new document. ControlInfo
holds information about controls hosted by ControlHostService
.
EventSequenceDocument
also implements ISearchableContext
to allow searching for data in DomNode
objects. For details on searching, see Node Searching.
The Editor
component is the client for event sequence documents.
Editor
uses the DocumentClientInfo
class to hold document editor information. The Info
property gets the DocumentClientInfo
from a static
variable:
public DocumentClientInfo Info
{
get { return DocumentClientInfo; }
}
/// <summary>
/// Information about the document client</summary>
public static DocumentClientInfo DocumentClientInfo = new DocumentClientInfo(
Localizer.Localize("Event Sequence"),
new string[] { ".xml", ".esq" },
Sce.Atf.Resources.DocumentImage,
Sce.Atf.Resources.FolderImage,
true);
CanOpen()
simply checks that the filename extension is suitable, using the DocumentClientInfo
:
public bool CanOpen(Uri uri)
{
return DocumentClientInfo.IsCompatibleUri(uri);
}
The Open()
method reads the document file's data and converts it into a tree of DomNode
objects. After that, it sets up the context and other information needed for the new document.
The initial phase of opening creates a DomNode
for the tree root and gets the file name:
public IDocument Open(Uri uri)
{
DomNode node = null;
string filePath = uri.LocalPath;
string fileName = Path.GetFileName(filePath);
For an existing document, a FileStream
is created and read. Because the document is stored as an XML document, you can use an DomXmlReader
to read data and convert it to a tree of DomNode
s. DomXmlReader.Read()
returns the root DomNode
of the tree it creates. For a new document, a DomNode
with the DomNodeType
of the event sequence root element — from the Schema
class — is created.
if (File.Exists(filePath))
{
// read existing document using standard XML reader
using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
DomXmlReader reader = new DomXmlReader(m_schemaLoader);
node = reader.Read(stream, uri);
}
}
else
{
// create new document by creating a Dom node of the root type defined by the schema
node = new DomNode(Schema.eventSequenceType.Type, Schema.eventSequenceRootElement);
}
Next, Open()
performs a series of ATF DOM set up operations to complete the open process:
EventSequenceDocument document = null;
if (node != null)
{
// Initialize Dom extensions now that the data is complete
node.InitializeExtensions();
EventSequenceContext context = node.As<EventSequenceContext>();
ControlInfo controlInfo = new ControlInfo(fileName, filePath, StandardControlGroup.Center);
context.ControlInfo = controlInfo;
// set document URI
document = node.As<EventSequenceDocument>();
document.Uri = uri;
// set document GUIs for search and replace
document.SearchUI = new DomNodeSearchToolStrip();
document.ReplaceUI = new DomNodeReplaceToolStrip();
document.ResultsUI = new DomNodeSearchResultsListView(m_contextRegistry);
context.ListView.Tag = document;
// show the ListView control
m_controlHostService.RegisterControl(context.ListView, controlInfo, this);
}
return document;
First, an EventSequenceDocument
object is created.
InitializeExtensions()
initializes all the DOM adapters defined in the schema loader, shown in Define DOM Extensions.
An EventSequenceContext
is created by adapting the root DomNode
to EventSequenceContext
, which is a DOM adapter for the "EventSequence" type. Recall that the "EventSequence" type is the type of the document's root.
The event sequence document's data is going to be displayed in a ListView
that is part of the EventSequenceContext
. A ControlInfo
is set up for this control and is placed in the EventSequenceContext
.
EventSequenceDocument
is also a DOM adapter for the "EventSequence" type, so the tree root DomNode
can be adapted to EventSequenceDocument
.
The EventSequenceDocument
also has some search properties set. For information about searching, see Node Searching.
The document
is saved in the context's ListView
for future reference:
context.ListView.Tag = document;
ListView
is a property of EventSequenceContext
that gets the ListView
control associated with the context.
Finally, the ListView
control is registered with the ControlHostService
component.
Save()
uses the capabilities of DomXmlWriter
to write the DomNode
tree to an XML file. DomXmlWriter
gets data model information from the schema so it knows how to write the DomNode
tree to XML with its Write()
method. The document is cast back to an EventSequenceDocument
to get its root DomNode
for Write()
.
public void Save(IDocument document, Uri uri)
{
string filePath = uri.LocalPath;
FileMode fileMode = File.Exists(filePath) ? FileMode.Truncate : FileMode.OpenOrCreate;
using (FileStream stream = new FileStream(filePath, fileMode))
{
DomXmlWriter writer = new DomXmlWriter(m_schemaLoader.TypeCollection);
EventSequenceDocument eventSequenceDocument = (EventSequenceDocument)document;
writer.Write(eventSequenceDocument.DomNode, stream, uri);
}
}
Closing the document entails cleaning up the contexts that were used:
public void Close(IDocument document)
{
EventSequenceContext context = Adapters.As<EventSequenceContext>(document);
m_controlHostService.UnregisterControl(context.ListView);
context.ControlInfo = null;
// close all active EditingContexts in the document
foreach (DomNode node in context.DomNode.Subtree)
foreach (EditingContext editingContext in node.AsAll<EditingContext>())
m_contextRegistry.RemoveContext(editingContext);
// close the document
m_documentRegistry.Remove(document);
}
The ListView
control in the EventSequenceContext
is unregistered.
Finally, any EditingContext
s that were created are removed from the ContextRegistry
, and the document is removed from the DocumentRegistry
.
Contexts are discussed in Working With Contexts.
Editor
also implements IControlHostClient
for the ListView
that is in the EventSequenceContext
. This requires it to handle the control's activation, deactivation, and close events.
The Activate()
method retrieves the EventSequenceDocument
from the Tag
in the ListView
it was stored in and sets it as the active document in the DocumentRegistry
component. It gets the EventSequenceContext
by adapting the document again and sets it as the active context with the ContextRegistry
:
void IControlHostClient.Activate(Control control)
{
EventSequenceDocument document = control.Tag as EventSequenceDocument;
if (document != null)
{
m_documentRegistry.ActiveDocument = document;
EventSequenceContext context = document.As<EventSequenceContext>();
m_contextRegistry.ActiveContext = context;
}
}
Close()
performs a similar operation to Activate()
, but with the aim of closing things out. To close the document, it uses the IDocumentService
in the variable m_documentService
, provided by the StandardFileCommands
component in this sample. If it succeeds, it then removes the context associated with the document from the ContextRegistry
.
bool IControlHostClient.Close(Control control)
{
bool closed = true;
EventSequenceDocument document = control.Tag as EventSequenceDocument;
if (document != null)
{
closed = m_documentService.Close(document);
if (closed)
m_contextRegistry.RemoveContext(document);
}
return closed;
}
Two components handle editing event sequences and their associated resources: EventListEditor
and ResourceListEditor
. Events and resources are edited by either dragging and dropping them from the palette onto a ListView
or deleting them from the ListView
. You can also edit events and resources with context menus in the ListView
or the application's Edit menu. Event and resource attributes can also be edited, but that falls under property editing, which is all performed by the PropertyEditor
, GridPropertyEditor
, and PropertyEditingCommands
components.
Document data is held in a tree of DomNode
s. The editor components freely adapt the document's root DomNode
to the various DOM adapters for the "EventSequence" type, such as EventSequenceDocument
and EventSequenceContext
, depending on what capabilities are needed.
EventListEditor
edits the event sequence document in a ListView
on a tab. Several documents can be opened at a time, one to each tab in the central window. There is an EventSequenceContext
for each document, and it owns the document's ListView
.
The EventListEditor
constructor sets up event handling for context changes, that is, tracking which ListView
is active:
m_contextRegistry.ActiveContextChanged += new EventHandler(contextRegistry_ActiveContextChanged);
m_contextRegistry.ContextAdded += new EventHandler<ItemInsertedEventArgs<object>>(contextRegistry_ContextAdded);
m_contextRegistry.ContextRemoved += new EventHandler<ItemRemovedEventArgs<object>>(contextRegistry_ContextRemoved);
The ActiveContextChanged
event handler, contextRegistry_ActiveContextChanged
, gets the current EventSequenceContext
and, if non-null
, uses it to obtain the ListView
settings and apply them to the newly active ListView
:
private void contextRegistry_ActiveContextChanged(object sender, EventArgs e)
{
if (m_eventSequenceContext != null)
m_listViewSettings = m_eventSequenceContext.ListViewAdapter.Settings;
m_eventSequenceContext = m_contextRegistry.GetMostRecentContext<EventSequenceContext>();
if (m_eventSequenceContext != null)
m_eventSequenceContext.ListViewAdapter.Settings = m_listViewSettings;
}
When an EventSequenceContext
is added for a new document, this event's handler subscribes the new context's ListView
to editing events:
private void contextRegistry_ContextAdded(object sender, ItemInsertedEventArgs<object> e)
{
EventSequenceContext context = Adapters.As<EventSequenceContext>(e.Item);
if (context != null)
{
context.ListView.DragOver += new DragEventHandler(listView_DragOver);
context.ListView.DragDrop += new DragEventHandler(listView_DragDrop);
context.ListView.MouseUp += new MouseEventHandler(listView_MouseUp);
context.ListViewAdapter.LabelEdited +=
new EventHandler<LabelEditedEventArgs<object>>(listViewAdapter_LabelEdited);
}
}
When an EventSequenceContext
is removed, all these events are unsubscribed from.
These editing event handlers do the actual editing. For instance, this is the listView_DragDrop
method that takes care of a DragDrop
event on the ListView
:
private void listView_DragDrop(object sender, DragEventArgs e)
{
IInstancingContext context = m_eventSequenceContext;
if (context.CanInsert(e.Data))
{
ITransactionContext transactionContext = context as ITransactionContext;
TransactionContexts.DoTransaction(transactionContext,
delegate
{
context.Insert(e.Data);
},
Localizer.Localize("Drag and Drop"));
if (m_statusService != null)
m_statusService.ShowStatus(Localizer.Localize("Drag and Drop"));
}
}
This method can treat the current EventSequenceContext
as an IInstancingContext
, because EventSequenceContext
implements IInstancingContext
. It uses this IInstancingContext
to check if the drag and drop editing operation can occur, that is, can the type represented by the dragged icon be inserted into the ListView
? If so, it uses a ITransactionContext
to perform the insertion, so that it can be undone if desired. Note that both the CanInsert()
and Insert()
methods are invoked on the IInstancingContext
. The methods actually invoked are in the IInstancingContext
implementation of EventSequenceContext
, discussed in EventSequenceContext Class. Also note that the ITransactionContext
can be used here, because one of the classes EventSequenceContext
derives from implements ITransactionContext
, as mentioned in EventSequenceContext Class.
The mouse up event is handled by listView_MouseUp
and checks for a right-button click to determine whether to display a context menu:
private void listView_MouseUp(object sender, MouseEventArgs e)
{
Control control = sender as Control;
object target = null; // TODO
if (e.Button == MouseButtons.Right)
{
IEnumerable<object> commands =
ContextMenuCommandProvider.GetCommands(
Lazies.GetValues(m_contextMenuCommandProviders), m_eventSequenceContext, target);
Point screenPoint = control.PointToScreen(new Point(e.X, e.Y));
m_commandService.RunContextMenu(commands, screenPoint);
}
}
The method uses ContextMenuCommandProvider.GetCommands()
to get any context commands. This is an extension method for the IContextMenuCommandProvider
interface for providers of context menu commands. There are two providers implementing IContextMenuCommandProvider
in this sample: StandardEditCommands
that implements the standard Edit menu's Cut, Copy, Paste, and Delete commands; and PropertyEditingCommands
that provides context commands for property editors. In this case, StandardEditCommands
is the provider; PropertyEditingCommands
provides context menu items in the property editors. These commands are displayed in a context menu by invoking RunContextMenu()
on the CommandService
component.
This component performs editing operations on the Resources ListView
control in the dialog, displaying the resources for the currently selected event. You can also drag resources from the palette onto this ListView
and edit them.
ResourceListEditor
is very similar to EventListEditor
and does pretty much the same things. This editor tracks editing events on a ListView
, such as drag and drop, and performs the operation when valid.
What differs is that there is only one ListView
control. Instead of belonging to a context, this ListView
is owned by the editor itself. This component's IInitializable.Initialize()
method creates the ListView
and initializes it: sets its properties, subscribes to editing events, and registers it with the ControlHostService
component, very similarly to how EventSequenceContext
sets up its ListView
. It also uses the SettingsServices
component to persist its ListView
settings.
void IInitializable.Initialize()
{
m_resourcesListView = new ListView();
m_resourcesListView.AllowDrop = true;
m_resourcesListView.MultiSelect = true;
m_resourcesListView.AllowColumnReorder = true;
m_resourcesListView.LabelEdit = true;
m_resourcesListView.Dock = DockStyle.Fill;
m_resourcesListView.DragOver += new DragEventHandler(resourcesListView_DragOver);
m_resourcesListView.DragDrop += new DragEventHandler(resourcesListView_DragDrop);
m_resourcesListView.MouseUp += new MouseEventHandler(resourcesListView_MouseUp);
m_resourcesListViewAdapter = new ListViewAdapter(m_resourcesListView);
m_resourcesListViewAdapter.LabelEdited +=
new EventHandler<LabelEditedEventArgs<object>>(resourcesListViewAdapter_LabelEdited);
m_resourcesControlInfo = new ControlInfo(
Localizer.Localize("Resources"),
Localizer.Localize("Resources for selected Event"),
StandardControlGroup.Bottom);
m_controlHostService.RegisterControl(m_resourcesListView, m_resourcesControlInfo, this);
if (m_settingsService != null)
{
SettingsServices.RegisterSettings(
m_settingsService,
this,
new BoundPropertyDescriptor(this, () => ListViewSettings, "ListViewSettings", "", "")
);
}
}
Because this ListView
shows the resources for the currently selected event, this component must track context changes. The ResourceListEditor
constructor subscribes to the ActiveContextChanged
event on the ContextRegistry
. Its handler, contextRegistry_ActiveContextChanged
, gets the current EventSequenceContext
and subscribes to its SelectionChanged
event, so that it is informed of event selection changes in the currently active document. It then calls UpdateEvent()
to update the ResourceListEditor
's ListView
. UpdateEvent()
determines the last selected event in the current event sequence document:
private void UpdateEvent()
{
Event nextEvent = null;
if (m_eventSequenceContext != null)
nextEvent = m_eventSequenceContext.Selection.GetLastSelected<Event>();
if (m_event != nextEvent)
{
// remove last event's editing context in case it was activated
if (m_event != null)
m_contextRegistry.RemoveContext(m_event.Cast<EventContext>());
m_event = nextEvent;
// get next event's editing context and bind to resources list view
EventContext eventContext = null;
if (nextEvent != null)
eventContext = nextEvent.Cast<EventContext>();
m_resourcesListViewAdapter.ListView = eventContext;
}
}
In this method, Event
refers to event data that is edited by this sample, not a subscribable event.
Because application data is in an ATF DOM, an event object is represented by a DomNode
. Such a DomNode
can be adapted to both Event
and EventContext
DOM node adapters, as indicated by this definition in the SchemaLoader
for the "Event" type:
Schema.eventType.Type.Define(new ExtensionInfo<Event>());
Schema.eventType.Type.Define(new ExtensionInfo<EventContext>());
Both these adaptations are used in the UpdateEvent()
method. This method gets the last selected event item in the current EventSequenceContext
's ListView
as an Event
in this line:
nextEvent = m_eventSequenceContext.Selection.GetLastSelected<Event>();
If nextEvent
is different from the previous Event
, m_event
, then m_event
is adapted to EventContext
and removed from the ContextRegistry
:
m_contextRegistry.RemoveContext(m_event.Cast<EventContext>());
Finally, the last selected event, nextEvent
, is adapted to EventContext
and used to update the ResourceListEditor
's ListView
:
if (nextEvent != null)
eventContext = nextEvent.Cast<EventContext>();
m_resourcesListViewAdapter.ListView = eventContext;
This last line sets the ListView
property, the list data in the ListView
. This property is a IListView
and EventContext
implements IListView
, so this assignment works.
SimpleDOMEditor employs two forms of DomNode
searching, provided by two components:
-
DomNodeNameSearchService
: a component in SimpleDOMEditor for searching and replacingDomNode
names in the currently active document. -
DomNodePropertySearchService
: an ATF component that searches for and replacesDomNode
names and attribute values using a regular expression in the currently active document.
DomNode
searching controls. Searching also uses the ATF DomNodeQueryable
DOM adapter.
DomNodeQueryable
is defined as a DOM adapter for the "EventSequence" type in SchemaLoader
, so any node in the tree can be searched:
Schema.eventSequenceType.Type.Define(new ExtensionInfo<DomNodeQueryable>());
DomNodeQueryable
implements several context interfaces to handle searching, displaying results, and replacing results:
-
IQueryableContext
: Define aQuery()
method to enumerate objects that satisfy the conditions of search predicates. -
IQueryableResultContext
: Access the results of a query and be notified when these results change. -
IQueryableReplaceContext
: Interface for classes in which containing objects can be replaced.
-
ISearchUI
: Interface for a client-defined UI that provides user controls for specifying search criteria, and for triggering a search on that criteria. -
IResultsUI
: Interface for a client-defined control that displays search results. -
IReplaceUI
: Interface for a client-defined control that allows a user to apply replacement data to search results.
Bind()
method that binds a control to the data the context represents: the above contexts are DOM adapters for the root DomNode
of the document.
DomNodeQueryable
uses DomNodeQueryMatch
to hold matching properties of a given DomNode
.
DomNodeNameSearchService
uses the DomNodeNameSearchControl
for its UI. This control was created in the Forms Designer using ATF controls. This control's InitializeComponent()
is, in part:
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DomNodeNameSearchControl));
this.domNodeSearchTextBox1 = new Sce.Atf.Dom.DomNodeNameSearchTextBox();
this.domNodeReplaceTextBox1 = new Sce.Atf.Applications.ReplaceTextBox();
this.domNodeSearchResultsListView1 = new Sce.Atf.Dom.DomNodeSearchResultsListView();
...
These new controls are added to the main control. DomNodeNameSearchTextBox
, for instance, is a simple TextBox
for specifying a DomNode
name search. DomNodeSearchResultsListView
(derived from SearchResultsListView
), also used by DomNodePropertySearchService
, displays search results in a ListBox
.
When the active context changes, this method is called:
private void contextRegistry_ActiveContextChanged(object sender, EventArgs e)
{
SearchUI.Bind(m_contextRegistry.GetActiveContext<IQueryableContext>());
ResultsUI.Bind(m_contextRegistry.GetActiveContext<IQueryableResultContext>());
ReplaceUI.Bind(m_contextRegistry.GetActiveContext<IQueryableReplaceContext>());
}
This method binds the controls to the data of the currently active context, so the controls work with the active data.
DomNodePropertySearchService
offers a more powerful search than DomNodeNameSearchService
. Its constructor creates a UserControl
and adds ATF controls that perform the DomNode
search: DomNodeSearchToolStrip
, DomNodeReplaceToolStrip
, and DomNodeSearchResultsListView
. For instance, DomNodeSearchToolStrip
provides a ToolStrip
for specifying a search on DomNode
s for both the name and other attributes, using regular expressions.
public DomNodePropertySearchService(
IContextRegistry contextRegistry,
IControlHostService controlHostService)
{
m_contextRegistry = contextRegistry;
m_controlHostService = controlHostService;
// define root control
m_rootControl = new UserControl();
m_rootControl.Name = "Search and Replace";
m_rootControl.SuspendLayout();
m_rootControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
// Create and add the search input control
SearchUI = new DomNodeSearchToolStrip();
SearchUI.Control.Dock = DockStyle.None;
m_rootControl.Controls.Add(SearchUI.Control);
SearchUI.UIChanged += UIElement_Changed;
// Create and add the replace input control
ReplaceUI = new DomNodeReplaceToolStrip();
ReplaceUI.Control.Dock = DockStyle.None;
m_rootControl.Controls.Add(ReplaceUI.Control);
ReplaceUI.UIChanged += UIElement_Changed;
// Create and add the results output control
ResultsUI = new DomNodeSearchResultsListView(m_contextRegistry);
ResultsUI.Control.Dock = DockStyle.None;
m_rootControl.Controls.Add(ResultsUI.Control);
ResultsUI.UIChanged += UIElement_Changed;
...
Search results are displayed in the ListBox
of a DomNodeSearchResultsListView
for both search components.
The following illustration shows a name search using DomNodeNameSearchService
, finding one DomNode
and displaying it in its ListView
. When the found node is selected in this ListView
hit list, the node's properties are displayed in both property editors. In addition, the "Name" value of the event that was found is highlighted in the property editors, which is the subselection.
These search components use the EventSequenceContext
for a subselection context, so an EventSequenceContext
must be the active context for these components' controls to be active. This means the main ListView
must be active, rather than the Resources ListView
, because the main ListView
uses an EventSequenceContext
, but the Resources ListView
uses EventContext
.
The PropertyView
class provides much of the capability of the property editors, as noted in Property Editor Containers. When a search result is selected in DomNodeSearchResultsListView
, this selection change event results in the following code being executed in PropertyView
:
ISubSelectionContext selectionContext = m_editingContext.As<ISubSelectionContext>();
ISelectionContext subSelectionContext = (selectionContext != null) ? selectionContext.SubSelectionContext : null;
if (subSelectionContext != null)
subSelectionContext.SelectionChanged += subSelectionContext_SelectionChanged;
The EventSequenceContext
in m_editingContext
is the currently active context, and it implements ISubSelectionContext
. This means that neither selectionContext
nor subSelectionContext
is null
, so the (sub)selection event is subscribed to, with the handler subSelectionContext_SelectionChanged
. This subselection change event is raised by the selection_Changed
method in GenericSelectionContext
when the selection changes in the DomNodeSearchResultsListView
. For details on GenericSelectionContext
, see ISubSelectionContext Interface and GenericSelectionContext Class.
The handler subSelectionContext_SelectionChanged
invalidates and refreshes the editing controls. It also calls PropertyView.OnSubSelectionChanged()
, which selects the property that is in the subselection, that is, the property that was found in the search. This results in the attribute standing out in the property editor, as seen in the previous illustration. In the Property Editor window, the name of the attribute ("Name") is highlighted; in the Grid Property Editor window, the attribute's value is marked bold.
- Circuit Editor Programming Discussion: Learn how ATF handles graphs, and provides editors for kinds of graphs, such as circuits.
- Code Editor Programming Discussion: Shows how to interface third party software to an ATF application: the ActiproSoftware SyntaxEditor.
- Diagram Editor Programming Discussion: Very simply combines components from the CircuitEditor, FsmEditor, and StateChartEditor samples into one application, with the abilities of all three, showing the power of components.
-
DOM Property Editor Programming Discussion: Shows how to use the ATF DOM with an XML Schema to define application data with a large variety of attribute types, whose values can be viewed and edited using the ATF
PropertyEditor
component, using various value editors to view and edit attributes. - DOM Tree Editor Programming Discussion: Shows how to edit DOM data using a tree control and display properties in a variety of value editors.
- File Explorer Programming Discussion: Discusses the ATF File Explorer Sample using list and tree controls with adapters.
- FSM Editor Programming Discussion: Tells you about how the ATF FSM Editor Sample edits simple graphs for state machines, using DOM adapters for contexts and validation.
-
Model Viewer Programming Discussion: Shows how the ATF Model Viewer Sample is written, discussing how ATGI and Collada model data is handled, using rendering components, and using a
DesignControl
as a canvas for rendering. -
Simple DOM Editor Programming Discussion: Programming the ATF Simple DOM Editor Sample, creating a palette, using DOM adapters and contexts, editing application data, and searching
DomNode
s. - Simple DOM Editor WPF Programming Discussion: Programming the ATF Simple DOM Editor WPF Sample, which is similar to ATF Simple DOM Editor Sample, but implemented using ATF's WPF framework.
- Simple DOM No XML Editor Programming Discussion: Programming the ATF Simple DOM No XML Editor Sample, which is very similar to ATF Simple DOM Editor Sample, except that it doesn't use XML for either its data model or persisting application data.
- State Chart Editor Programming Discussion: Shows using ATF graph and other classes to create a statechart editor, using DOM adapters, documents, contexts, and validators.
- Target Manager Programming Discussion: Description of how a target manager is implemented using ATF components to manage target devices, such as PlayStation®Vita or PS3™ consoles. A target manager is used in other tools, such as the StateMachine tool.
- Timeline Editor Programming Discussion: Discusses how to create a fairly full-featured timeline editor using the ATF timeline facilities, such as the timeline renderer and the timeline control and its manipulators.
-
Tree List Control Programming Discussion: Demonstrates using the
TreeListControl
andTreeListItemRenderer
classes to display and edit hierarchical data in a tree view with details in columns. -
Tree List Editor Programming Discussion: Demonstrates how to use the ATF tree controls
TreeListView
and its enhancement,TreeListViewEditor
.TreeListView
usesTreeListViewAdapter
, which adaptsTreeListView
to display data in a tree. - Using Dom Programming Discussion: Shows how to use the various parts of the ATF DOM: an XML Schema, a schema metadata class file generated by DomGen, DOM adapters for the data types, a schema loader, and saving application data to an XML file.
- Home
- Getting Started
- Features & Benefits
- Requirements & Dependencies
- Gallery
- Technology & Samples
- Adoption
- News
- Release Notes
- ATF Community
- Searching Documentation
- Using Documentation
- Videos
- Tutorials
- How To
- Programmer's Guide
- Reference
- Code Samples
- Documentation Files
© 2014-2015, Sony Computer Entertainment America LLC