Library tutorials & articles
Hosting Windows Forms Designers
- Introduction
- The Service Hierarchy
- The Designer Container & Host
- Starting Off
- Implementing ISite and more
- Extender Services
- Making it Work
Implementing ISite and more
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 grabISelectionServiceand 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 usingIComponentChangeServiceto let others know what is going on as the component is being removed. -
CreateTransaction- Creates an instance of our templateDesignerTransactionclass (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 anITypeResolutionServiceavailable, and if so use it. If not, returnType.GetType()instead. -
Container- Just return the instance of the class since it implementsIContaineritself. -
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.
Related articles
Related discussion
-
Binary Studio | software development outsourcing Ukraine
by shane124 (4 replies)
-
Chart insertation in a windows form...
by pdhanik (1 replies)
-
Point of Sale Developers: Hardware & C# SDK
by ManiGovindan (7 replies)
-
help with the remote frame buffer protocol from real VNC
by poison (0 replies)
-
Need help making a complete program editable, C# or .net I think
by davelee (1 replies)
Related podcasts
-
A Practical Look at Silverlight 2 Part 1
Now that Silverlight 2 is at the Olympics and making a big splash, we wanted to explore this fascinating technology more. Microsoft Silverlight 2 is a cross-browser, cross-platform, and cross-device plug-in for delivering the next generation of .NET based media experiences and rich interactive ap...
Events coming up
-
Dec
9
GL.net Group Meeting - December 2009
Gloucester, United Kingdom
The beginning of this year holiday season will belong to mocks. Ronnie and Stephen will take us for a tour around exciting world of unit testing.
How would I go about saving a form that I have designed?
!--removed tag-->I have (am still) modifying this code to create a stand-alone Xaml generator for forms. The Xaml is structured for direct consumption by Windows Presentation Foundation. This was a great starting place.
In the course of my modifications and testing, I found a couple of bugs in the code which you may wish to correct in your source.
The Name property is listed twice in the property grid.
If you add a control (i.e. a Button), then change the name from the default (Button1) to anything else, then add another button, you get an unhandled exception. This does not occur if all like controls are added first then the names are modified. The cause is when the control is first added to the designer, it is added to the DesignerHost components collection using the default (Button1) control name as a key. When the Name property is updated, the components collection is not. When adding a second like control, the DesignerHost attempts to add it using the default name as well. However, since the first control was renamed, the default name of the second control is the same as it was for the first (Button1). An unhandled exception is thrown when the second control is added because the components collection already contains a control with the same key value.
I corrected this by attaching a handler to the PropertyValueChanged event of the PropertyGrid which removes the original entry for the control and readds it with the new name as the key whenever the Name property value is changed.
how to change Designer for design PocketPC components?
htx
v!tek
Hi Tim, great article. I am currently creating a designer in a similar manner to your article, used to create pdf files. I am using it to add only textboxes and pictures, and can save the data to a database. However I need to bring back the objects and add them to the form programmatically so the user can edit the objects (change the positions etc) Do you know how (or explain how) to add items to the designer surface programmatcally without using the drag and drop from the toolbox
Thanks
John Harry
Tim:
Thanks for your nice article.
How can I get the location of a control in the design surface. I want to show the coordinates when the user moves the control, but I can't figure how!
Did you figure it out how to persist the designer content? I would appreciate any help on this
Thanks
Sgirase
Hi!
That article is really great. It gave me useful hints to start my application in perfectmanner , which looks like an .Net IDE . but can you please tell me how to remove a control from the designer form ....
Hello Tim,
Thank you very much for this excellent article.
We have developed a graphical macro language in C# for our customers and one of the remaining hurdles that we have is the ability to edit the location of controls on a runtime form.
When the customer wants to edit our form, we scan our macro and generate controls on the form based upon the macro content.
We would then like to display that form with the controls where the customer can position and size those controls like you can in this Designer example. We would then iterate through the list of controls and remember their locations and sizes within the macro.
Can you please lead us in the right direction? We have been searching, trying, and reading many examples to no avail. It appears that you possess this knowledge and could help us. We are not inexperienced developers, I personally have been a software developer for 22 years in many languages.
For example, how would you modify this example so that controls can be placed on the form with out the user clicking on the designer surface?
Thank you very much for your reply,
Rick Wirch
Good question ... I am actually tasked with building a Web Forms Designer. I can load ASP.NET controls into my toolbox but of course can't drop those controls onto a Windows forms. Can somebody help me!!
Much appreciated -
Jon
Is it possible to use a treeview for that?
That article is really great.
It gave me the needed hints to step into this subject as deep as I wanted to. As i'm currently trying tom write a lightweight IDE for customumizing my own applications, i need to know, how the content auf the designer could be persisted and reloaded.
Is there any standard-mechanism for that, or will I have to implement my own handlers?
Any help would be appreciated!
Its possible to do something similar to your example using web forms designer?
This article is simply great. I wish to see more like this one.
Arthur
This thread is for discussions of Hosting Windows Forms Designers.