-
Notifications
You must be signed in to change notification settings - Fork 262
Context Registry
The context registry tracks all context interface or class objects in an application, maintaining a collection of contexts. In particular, the registry tracks the active context, which is usually determined by the currently active control. The IContextRegistry
interface provides the framework to do all of this.
IContextRegistry
contains the following items that help an application keep track of contexts, including the active one:
-
Contexts
property: Get an enumeration of all open contexts, that is, all objects that implement context interfaces and have been added to the context registry. -
ActiveContext
property: Get or set the active context. -
GetActiveContext<T>()
: Get the active context as the given type. -
GetMostRecentContext<T>()
: Get the most recently active context of the given type, which may not be the same asActiveContext
. -
RemoveContext()
: Remove the given context from the registry. -
ActiveContextChanging
andActiveContextChanged
: Events before and after the active context changes. -
ContextAdded
andContextRemoved
: Events to indicate a context has been added to or removed from the registry.
ActiveContext
property also adds the context to the registry; there is no method to simply add a context to the registry.
ATF's ContextRegistry
component implements the IContextRegistry
interface. Most applications need to use this component or one like it, so they can determine what operations are meaningful in any given context. You can create your own ContextRegistry
component by implementing the IContextRegistry
interface.
ContextRegistry
uses AdaptableActiveCollection
, an extension of ActiveCollection
, as a container for contexts. ActiveCollection
handles the collection per se. AdaptableActiveCollection
allows adapting contexts to other types, because a given context object may implement several context interfaces.
The ContextRegistry
is often passed as one of the parameters in the ImportingConstructor
of components used in an application. The constructor can then save this instance for later use. The ContextRegistry
object can also be obtained other ways, as with the System.ComponentModel.Composition.Hosting.ExportProvider
class, discussed in How MEF is Used in ATF.
As previously mentioned, IContextRegistry
doesn't have a method to add contexts to the registry; setting the active context adds that context to the registry.
For instance, the Editor
class of the ATF Simple DOM Editor Sample creates and saves documents that contain sequences of events. Editor
also serves as the control host client for the ListView
control that displays document data. When the ListView
is activated by the user clicking on it, the control's Activate()
method is called:
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;
}
}
This method adapts the EventSequenceDocument
document
to a context for the event sequence, EventSequenceContext
, and then sets the IContextRegistry.ActiveContext
property to this context to make it the active context. If this context is not already in the context registry, it is added.
A control becoming active is a common way to set the active context
When a context is no longer needed, it should be removed from the registry. For instance, a context associated with a document may be removed from the registry once the document is closed. The Editor
class in the ATF Simple DOM Editor Sample does precisely that when the document successfully closes:
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;
}
An application often needs to track context changes, so it subscribes to IContextRegistry
events. A component's constructor or IInitializable.Initialize()
method could subscribe to events in IContextRegistry
.
The EventListEditor
component of the ATF Simple DOM Editor Sample tracks contexts and also handles drag and drop and right-click context menus for a ListView
control. In this sample, the component subscribes to several IContextRegistry
events in its constructor:
public EventListEditor(
IControlHostService controlHostService,
ICommandService commandService,
IContextRegistry contextRegistry)
{
m_controlHostService = controlHostService;
m_commandService = commandService;
m_contextRegistry = contextRegistry;
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);
}
...
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);
}
}
In this case, the ContextAdded
event handler, contextRegistry_ContextAdded
, takes the opportunity to subscribe to various events on the ListView
control associated with the context. The ContextRemoved
handling method unsubscribes from these events.
For more information on context handling in this sample, see Simple DOM Editor Programming Discussion.
In the following example, the DomRecorder
component initially obtains the ContextRegistry
instance using a MEF import:
[Import(AllowDefault = true)]
public IContextRegistry ContextRegistry
{
get { return m_contextRegistry; }
set
{
if (m_contextRegistry != null)
m_contextRegistry.ActiveContextChanged -= m_contextRegistry_ActiveContextChanged;
m_contextRegistry = value;
if (m_contextRegistry != null)
m_contextRegistry.ActiveContextChanged += m_contextRegistry_ActiveContextChanged;
}
}
...
private void m_contextRegistry_ActiveContextChanged(object sender, EventArgs e)
{
ValidationContext = m_contextRegistry.ActiveContext.As<IValidationContext>();
}
After the active context changes, the handler m_contextRegistry_ActiveContextChanged
sets the ValidationContext
property to the active context, adapted to an IValidationContext
. Instead of using the ActiveContext
property, this event handler could also have called GetActiveContext<IValidationContext>()
.
It is useful to determine whether the active context supports a given context interface, so the application can determine what operations are meaningful in the current context. For example, the RenameCommand
component tests whether it can perform a rename command by checking the available context interfaces:
bool ICommandClient.CanDoCommand(object commandTag)
{
// The dialog box is modal and not dockable, so only allow it to pop up if it can be used.
bool canDo = false;
if (Command.Rename.Equals(commandTag))
{
// Note that the ITransactionContext can be null, so we don't need to check it here.
var selectionContext = m_contextRegistry.GetActiveContext<ISelectionContext>();
var namingContext = m_contextRegistry.GetActiveContext<INamingContext>();
if (selectionContext != null &&
namingContext != null)
{
foreach (object item in selectionContext.Selection)
{
if (namingContext.CanSetName(item))
{
canDo = true;
break;
}
}
}
}
return canDo;
}
This method calls GetActiveContext()
to adapt the active context to selection and naming context interfaces. It checks that both these contexts be non-null
to be able to rename objects, which is a sensible requirement.
In this example from the StandardEditCommands
component, GetActiveContext()
returns an IInstancingContext
interface object, which is then adapted to an ITransactionContext
, so that context interface is required, too:
public void Paste()
{
IInstancingContext instancingContext = m_contextRegistry.GetActiveContext<IInstancingContext>();
if (instancingContext != null &&
instancingContext.CanInsert(Clipboard))
{
ITransactionContext transactionContext = instancingContext.As<ITransactionContext>();
transactionContext.DoTransaction(
delegate
{
instancingContext.Insert(Clipboard);
}, CommandInfo.EditPaste.MenuText);
OnPasted(EventArgs.Empty);
}
}
Note that GetActiveContext()
returns the actual context object. It is first adapted to an IInstancingContext
and then adapted to ITransactionContext
. The object's underlying class must therefore implement ITransactionContext
for this to work.
- What is a Context: Define contexts and discuss how ATF provides services for them.
-
Context Registry: The
ContextRegistry
component tracks all context objects in an application. - Context Interfaces: ATF's context interfaces and their usage.
- Context Classes: Classes that implement services for a context.
- Context Related Classes: Classes that use context interfaces and classes for their operation.
- Implementing a Context Interface: Implementing context interfaces.
- 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