Implementing ISite
Our ISite
implementation, called DesignSite
, is going to be a poweful little beast that also implements IDictionaryService
, the interface that for some reason some components use instead of using their own internal dictionaries. There isn't really much point going in to any of the stuff in this class in detail because it's mostly just template code except in the setter for the Name
property.
The setter needs to check there isn't already a component with the name passed in the container. If there isn't, it can then proceed. To play friendly with the rest of the design environment, it must cause the IComponentChangeService implementation to raise the OnComponentChanging
, OnComponentRename
and OnComponentChanged
events in that order while the change is made.
Implementing IComponentChangeService
This is an easy one. All this interface has is seven events and two methods which raise two of the events. All we do is add code for those two methods, and add another, internal method which is needed for our DesignSite
class to raise the ComponentRename
event. Although implementing this interface is easy, what's hard is working out where else in our implemented code to raise the events on it.
public void OnComponentChanged(object component, System.ComponentModel.MemberDescriptor
member, object oldValue, object newValue)
{
if (ComponentChanged != null)
ComponentChanged(this, new ComponentChangedEventArgs(component,
member, oldValue, newValue));
}
public void OnComponentChanging(object component,
System.ComponentModel.MemberDescriptor member)
{
if (ComponentChanging != null)
ComponentChanging(this, new ComponentChangingEventArgs(component, member));
}
internal void OnComponentRename(object component, string oldName, string newName)
{
if (ComponentRename != null)
ComponentRename(this, new ComponentRenameEventArgs(component,
oldName, newName));
}
public event System.ComponentModel.Design.ComponentEventHandler ComponentAdded;
public event System.ComponentModel.Design.ComponentEventHandler ComponentAdding;
public event System.ComponentModel.Design.ComponentChangedEventHandler ComponentChanged;
public event System.ComponentModel.Design.ComponentChangingEventHandler ComponentChanging;
public event System.ComponentModel.Design.ComponentEventHandler ComponentRemoved;
public event System.ComponentModel.Design.ComponentEventHandler ComponentRemoving;
public event System.ComponentModel.Design.ComponentRenameEventHandler ComponentRename;
Implementing IDesignerHost
This should really have been the class we started with, but IDesignerHost
, IContainer
, ISite
and IComponentChangeService
all depend on each other so much it makes sense to write about them in the order it's necessary to code them in. I'll cover the implementations of the members on IDesignerHost as I write them as best I can.
-
Activate
- This method is called to activate the root component. Our implementation will grabISelectionService
and set the root component as the primary selection. -
CreateComponent
- This method is used by designers to have the host environment create an instance of a class that is to be situated on the design surface. Calling it is functionally identical to creating instance themselves then adding it to the container. -
DestroyComponent
- This is called to remove a component from the design surface and dispose of it properly. This method is also responsible for usingIComponentChangeService
to let others know what is going on as the component is being removed. -
CreateTransaction
- Creates an instance of our templateDesignerTransaction
class (I'll come on to that in a minute) and adds it to the stack of transactions. -
GetDesigner
- We just use our designers hashtable to return the designer associated with the passed component. -
GetType
- We check if there is anITypeResolutionService
available, and if so use it. If not, returnType.GetType()
instead. -
Container
- Just return the instance of the class since it implementsIContainer
itself. -
InTransaction
- Return true if the number of transactions in our stack is greater than zero. -
Loading
- For this example we are not concerned with loading hosts, so just return false. -
RootComponent
- Return rootComponent, the first component added to our container. -
RootComponentClassName
- Return the name of the class the first component added to our container was created from. -
TransactionDescription
- Return the name of the transaction at the top of our stack, if there is one.
Designer Transactions
Every small change to a component should go through the IComponentChangeService
, but when lots of small changes need to be wrapped up logically, that's where designer transactions come in. If we were writing a full-scale implementation of a design environment, we would keep track of these for undo/redo support.
There is no interface to be implemented here, we just need to inherit the abstract class DesignerTransaction
with our own. All ours will do is make sure the appropriate events are raised by the host when the transaction is committed or cancelled.
Comments