pascalabcnet/VisualPascalABCNET/SSYY/SampleDesignerHost.cs

1652 lines
65 KiB
C#
Raw Normal View History

2015-05-14 22:35:07 +03:00
//------------------------------------------------------------------------------
/// <copyright from='1997' to='2002' company='Microsoft Corporation'>
/// Copyright (c) Microsoft Corporation. All Rights Reserved.
///
/// This source code is intended only as a supplement to Microsoft
/// Development Tools and/or on-line documentation. See these other
/// materials for detailed information regarding Microsoft code samples.
///
/// </copyright>
//------------------------------------------------------------------------------
namespace SampleDesignerHost
{
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Collections;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Drawing.Design;
using System.Reflection;
using System.Text;
using System.Collections.Generic;
using System.Drawing;
public class SampleDesignerHost :
IContainer
, IDesignerHost
, IDesignerLoaderHost
, IComponentChangeService
, IExtenderProviderService
, IDesignerEventService
{
// Service objects we are responsible for
internal ISelectionService selectionService; // selection services
private IMenuCommandService menuCommandService; // the menu command service
private IHelpService helpService; // the help service - UNIMPLEMENTED
private IReferenceService referenceService; // service to maintain references - UNIMPLEMENTED
private IMenuEditorService menuEditorService; // Menu editor service - UNIMPLEMENTED
private IToolboxService toolboxService; // toolbox service
// User attached events, designers and services.
private IServiceContainer serviceContainer; // holds global services users have added
private Hashtable designerTable; // holds component<->designer mappings
// The current Form Design
private DesignerLoader designerLoader; // the loader that reads/writes the document
private Hashtable sites; // name -> DesignSite mapping
private DesignerComponentCollection components; // public component collection. Tracks sites table.
private ArrayList extenderProviders; // extenders that are on the current form
private IComponent rootComponent; // the base document component we're designing
NETXP.Controls.ComboBoxExItem[] savedAllComponents = null;
internal Dictionary<IComponent, NETXP.Controls.ComboBoxExItem> savedComponentItems = null;
internal Dictionary<NETXP.Controls.ComboBoxExItem, IComponent> savedItemsComponent = null;
private string rootComponentClassName; // the name of the class the base component represents
private IRootDesigner rootDesigner; // the designer for the document
private SampleDocumentWindow documentWindow; // the thing being reparented by the docwin
private ITypeResolutionService typeResolver; // The object we load types through.
private Exception loadError; // The first load error, or null.
private INameCreationService nameService; // service we use to validate names of things.
private int transactionCount; // >0 means we're doing a transaction
private StringStack transactionDescriptions; // string descriptions of the current transactions
// Flags that determine the validity of our code...are we in sync?
private bool loadingDesigner; // true if we are loading
private bool reloading; // true if we are reloading the document
// Transient stuff
private SampleDesignSite newComponentSite; // used during new component creation
public static Dictionary<Type, int> componentBitmaps = new Dictionary<Type, int>();
private static ImageList controlImages = new ImageList();
public Dictionary<IComponent, NETXP.Controls.ComboBoxExItem> componentItems = new Dictionary<IComponent, NETXP.Controls.ComboBoxExItem>();
public Dictionary<NETXP.Controls.ComboBoxExItem, IComponent> itemsComponent = new Dictionary<NETXP.Controls.ComboBoxExItem, IComponent>();
internal NETXP.Controls.ComboBoxEx currentComponentsCombo;
//SampleDesignerHost
public SampleDesignerHost() : this(new ServiceContainer()) {
}
// We take a service provider in our constructor so that our main form can give us
// services (like the property grid and toolbox).
public SampleDesignerHost(IServiceProvider parentProvider) {
this.serviceContainer = new ServiceContainer(parentProvider);
designerTable = new Hashtable();
sites = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
loadingDesigner = false;
transactionCount = 0;
reloading = false;
// Services that we already have implemented on our object
serviceContainer.AddService(typeof(IDesignerHost), this);
serviceContainer.AddService(typeof(IContainer), this);
serviceContainer.AddService(typeof(IComponentChangeService), this);
serviceContainer.AddService(typeof(IExtenderProviderService), this);
serviceContainer.AddService(typeof(IDesignerEventService), this);
// And services that we demand create.
ServiceCreatorCallback callback = new ServiceCreatorCallback(this.OnCreateService);
serviceContainer.AddService(typeof(IToolboxService), callback);
serviceContainer.AddService(typeof(ISelectionService), callback);
serviceContainer.AddService(typeof(ITypeDescriptorFilterService), callback);
serviceContainer.AddService(typeof(IMenuCommandService), callback);
// serviceContainer.AddService(typeof(IMenuEditorService), callback); - UNIMPLEMENTED
// serviceContainer.AddService(typeof(IHelpService), callback); - UNIMPLEMENTED
// serviceContainer.AddService(typeof(IReferenceService), callback); - UNIMPLEMENTED
// serviceContainer.AddService(typeof(IPropertyValueUIService), callback); - UNIMPLEMENTED
// Configure extender providers.
((IExtenderProviderService)this).AddExtenderProvider(new SampleNameExtenderProvider(this));
((IExtenderProviderService)this).AddExtenderProvider(new SampleInheritedNameExtenderProvider(this));
//defaultMenuCommands = new DefaultMenuCommands(this);
//defaultMenuCommands.AddTo(menuCommandService);
// +Add Serialization Service
serviceContainer.AddService(typeof(IDesignerSerializationService), callback);
// -Add Serialization Service
currentComponentsCombo = new NETXP.Controls.ComboBoxEx();
currentComponentsCombo.Visible = false;
VisualPascalABC.Form1.Form1_object.PropertiesWindow.GetComponentsComboPanel().Controls.Add(currentComponentsCombo);
currentComponentsCombo.EnableMRU = false;
currentComponentsCombo.Dock = DockStyle.Fill;
NETXP.Controls.ComboBoxEx baseCombo = VisualPascalABC.Form1.Form1_object.PropertiesWindow.GetComponentsCombo();
currentComponentsCombo.ItemHeight = baseCombo.ItemHeight;
currentComponentsCombo.Font = baseCombo.Font;
currentComponentsCombo.DrawMode = baseCombo.DrawMode;
currentComponentsCombo.DropDownStyle = baseCombo.DropDownStyle;
currentComponentsCombo.Flags = baseCombo.Flags;
currentComponentsCombo.SelectedIndexChanged += new EventHandler(currentComponentsCombo_SelectedIndexChanged);
currentComponentsCombo.Visible = true;
currentComponentsCombo.ImageList = controlImages;
}
private void currentComponentsCombo_SelectedIndexChanged(object sender, EventArgs e)
{
if (currentComponentsCombo.SelectedItem == null) return;
IComponent comp = itemsComponent[currentComponentsCombo.SelectedItem as NETXP.Controls.ComboBoxExItem];
selectionService.SetSelectedComponents(new IComponent[] { comp });
}
public void SetSelectedComponents(object[] selection)
{
switch (selection.Length)
{
case 0:
currentComponentsCombo.SelectedItem = null;
break;
case 1:
currentComponentsCombo.SelectedItem = componentItems[selection[0] as IComponent];
break;
default:
currentComponentsCombo.SelectedItem = null;
break;
}
}
public static string getComboText(IComponent comp)
{
if (comp.Site != null)
{
return comp.Site.Name + ": " + comp.GetType().FullName;
}
else
{
return comp.GetType().FullName;
}
}
public void AddDesignedComponent(IComponent comp)
{
int num = -1;
Type type = comp.GetType();
if (!componentBitmaps.TryGetValue(type, out num))
{
ToolboxBitmapAttribute tba = TypeDescriptor.GetAttributes(type)[typeof(ToolboxBitmapAttribute)] as ToolboxBitmapAttribute;
if (tba == null)
{
num = -1;
}
else
{
num = currentComponentsCombo.ImageList.Images.Count;
currentComponentsCombo.ImageList.Images.Add(tba.GetImage(type));
}
componentBitmaps.Add(type, num);
}
NETXP.Controls.ComboBoxExItem it = new NETXP.Controls.ComboBoxExItem(num, getComboText(comp), 0);
currentComponentsCombo.Items.Add(it);
componentItems.Add(comp, it);
itemsComponent.Add(it, comp);
}
public void DeleteDesignedComponent(IComponent comp)
{
NETXP.Controls.ComboBoxExItem it;
bool exist = componentItems.TryGetValue(comp, out it);
if (!exist) return;
currentComponentsCombo.Items.Remove(it);
itemsComponent.Remove(componentItems[comp]);
componentItems.Remove(comp);
}
//****
//****
//**** IDisposable Implementation
//****
//****
/// Disposes of the DesignContainer. This cleans up any objects we may be holding
/// and removes any services that we created.
public void Dispose() {
// Dispose the loader before destroying the designer. Otherwise, the
// act of destroying all the components on the designer surface will
// be reflected in the loader, deleting the user's file.
if (designerLoader != null) {
try
{
designerLoader.Flush();
}
catch (Exception e1)
{
Debug.Fail("Designer loader '" + designerLoader.GetType().Name + "' threw during Flush: " + e1.ToString());
e1 = null;
}
try {
designerLoader.Dispose();
}
catch (Exception e2) {
Debug.Fail("Designer loader '" + designerLoader.GetType().Name + "' threw during Dispose: " + e2.ToString());
e2 = null;
}
designerLoader = null;
}
// Unload the document.
UnloadDocument();
// No services after this!
serviceContainer = null;
// Now tear down all of our services.
if (menuEditorService != null) {
IDisposable d = menuEditorService as IDisposable;
if (d != null) d.Dispose();
menuEditorService = null ;
}
if (selectionService != null) {
IDisposable d = selectionService as IDisposable;
if (d != null) d.Dispose();
selectionService = null;
}
if (menuCommandService != null) {
IDisposable d = menuCommandService as IDisposable;
if (d != null) d.Dispose();
menuCommandService = null;
}
if (toolboxService != null)
{
IDisposable d = toolboxService as IDisposable;
if (d != null) d.Dispose();
toolboxService = null;
}
if (helpService != null) {
IDisposable d = helpService as IDisposable;
if (d != null) d.Dispose();
helpService = null;
}
if (referenceService != null) {
IDisposable d = referenceService as IDisposable;
if (d != null) d.Dispose();
referenceService = null;
}
// Destroy our document window.
if (documentWindow != null) {
documentWindow.Dispose();
documentWindow = null;
}
}
//****
//****
//**** IContainer Implementation
//****
//****
// Properties
ComponentCollection IContainer.Components {
get {
if (components == null) {
components = new DesignerComponentCollection(this);
}
return components;
}
}
// Methods
/// Adds the given component to the Designer. This sets up the lifetime and site
/// relationship between component / container and then adds the new component
/// to the formcore and code buffer.
/// This will fabricate a default name for the component.
void IContainer.Add(IComponent component) {
((IContainer)this).Add(component, null);
}
void IContainer.Add(IComponent component, string name) {
if (null == component) return;
if (rootComponent != null) {
// Compare to the class the root component represents, not it's actual class!
if (String.Compare(component.GetType().FullName, rootComponentClassName, true) == 0) {
Exception ex = new Exception("Can't add a component to itself " + component.GetType().FullName);
throw ex;
}
}
ISite site = component.Site;
// If the component is already added to us, all we have to do is check
// the name. If the name is different we rename it, otherwise we do
// nothing.
if (site != null && site.Container == this) {
if (name != null && !name.Equals(site.Name)) {
CheckName(name);
site.Name = name;
}
return;
}
// Check to see if someone has already configured a site for us. If so,
// use it. Otherwise, fabricate a new site.
// newComponentSite is created by CreateComponent.
SampleDesignSite newSite = newComponentSite;
newComponentSite = null;
if (newSite != null && name == null) {
name = newSite.Name;
}
// Make sure the name is valid.
if (name != null) {
CheckName(name);
}
ComponentEventArgs ce = new ComponentEventArgs(component);
OnComponentAdding(ce);
// Remove this component from its current site
if (site != null) site.Container.Remove(component);
if (newSite == null) {
newSite = new SampleDesignSite(this, name);
}
// And set the relationship between this site and it's component. If the
// site has no name at this point, it will fabricate one.
newSite.SetComponent(component);
// If we were given a site, the name we're given should always be null,
// or at least be the same name as that stored in the new site.
Debug.Assert(name == null || name.Equals(newSite.Name), "Name should match the one in newComponentSite");
if (component is IExtenderProvider &&
!TypeDescriptor.GetAttributes(component).Contains(InheritanceAttribute.InheritedReadOnly)) {
((IExtenderProviderService)this).AddExtenderProvider((IExtenderProvider)component);
}
// And establish the component/site relationship
sites[newSite.Name] = newSite;
component.Site = newSite;
if (components != null) {
components.Add(newSite);
}
try {
CreateComponentDesigner(component);
// The component has been added. Note that it is tempting to move this above the
// designer because the designer will never need to know that its own component just
// got added, but this would be bad because the designer is needed to extract
// shadowed properties from the component.
//
OnComponentAdded(ce);
}
catch (Exception) {
// If we're loading, then don't remove the component. We are about to
// fail the load anyway here, and we don't want to be firing remove events during
// a load.
if (!loadingDesigner) {
((IContainer)this).Remove(component);
}
throw;
}
}
void IContainer.Remove(IComponent component) {
if (component == null) return;
ISite site = component.Site;
if (!sites.ContainsValue(site)) return;
if (site == null || site.Container != this) return;
if (!(site is SampleDesignSite)) return;
ComponentEventArgs ce = new ComponentEventArgs(component);
OnComponentRemoving(ce);
SampleDesignSite csite = (SampleDesignSite)site;
if (csite.Component != rootComponent) {
if (component is IExtenderProvider) {
((IExtenderProviderService)this).RemoveExtenderProvider((IExtenderProvider)component);
}
}
// and remove it's designer, should one exist.
IDesigner designer = (IDesigner)designerTable[component];
if (designer != null) {
designer.Dispose();
}
designerTable.Remove(component);
sites.Remove(csite.Name);
if (components != null) {
components.Remove(site);
}
// By this time, the component is dead. If someone
// threw an exception, there's nothing we can do about it.
//
try {
OnComponentRemoved(ce);
}
catch (Exception) {
}
// Finally, rip the site instance.
//
component.Site = null;
}
//****
//****
//**** IServiceProvider Implementation
//****
//****
object IServiceProvider.GetService(Type serviceType) {
Debug.Assert(serviceContainer != null, "We have no sevice container. Either the host has not been initialized yet or it has been disposed.");
object service = null;
if (serviceContainer != null) {
service = serviceContainer.GetService(serviceType);
// Record the success or failure of service requests in case someone
// wants to see in the Main Form.
//
SampleDesignerApplication.ServiceRequests requests = (SampleDesignerApplication.ServiceRequests)serviceContainer.GetService(typeof(SampleDesignerApplication.ServiceRequests));
if (requests != null)
{
if (service != null)
{
requests.ServiceSucceeded(serviceType);
}
else
{
requests.ServiceFailed(serviceType);
}
}
}
return service;
}
//****
//****
//**** IServiceContainer Implementation
//****
//****
void IServiceContainer.AddService(Type serviceType, ServiceCreatorCallback callback) {
Debug.Assert(serviceContainer != null, "We have no sevice container. Either the host has not been initialized yet or it has been disposed.");
if (serviceContainer != null) {
serviceContainer.AddService(serviceType, callback);
}
}
void IServiceContainer.AddService(Type serviceType, ServiceCreatorCallback callback, bool promote) {
Debug.Assert(serviceContainer != null, "We have no sevice container. Either the host has not been initialized yet or it has been disposed.");
if (serviceContainer != null) {
serviceContainer.AddService(serviceType, callback, promote);
}
}
void IServiceContainer.AddService(Type serviceType, object serviceInstance) {
Debug.Assert(serviceContainer != null, "We have no sevice container. Either the host has not been initialized yet or it has been disposed.");
if (serviceContainer != null) {
serviceContainer.AddService(serviceType, serviceInstance);
}
}
void IServiceContainer.AddService(Type serviceType, object serviceInstance, bool promote) {
Debug.Assert(serviceContainer != null, "We have no sevice container. Either the host has not been initialized yet or it has been disposed.");
if (serviceContainer != null) {
serviceContainer.AddService(serviceType, serviceInstance, promote);
}
}
void IServiceContainer.RemoveService(Type serviceType) {
if (serviceContainer != null) {
serviceContainer.RemoveService(serviceType);
}
}
void IServiceContainer.RemoveService(Type serviceType, bool promote) {
if (serviceContainer != null) {
serviceContainer.RemoveService(serviceType, promote);
}
}
//****
//****
//**** IDesignerLoaderHost Implementation
//****
//****
// Methods
/// This is called by the designer loader to indicate that the load has
/// terminated. If there were errors, they should be passed in the errorCollection
/// as a collection of exceptions (if they are not exceptions the designer
/// loader host may just call ToString on them). If the load was successful then
/// errorCollection should either be null or contain an empty collection.
void IDesignerLoaderHost.EndLoad(string baseClassName, bool successful, ICollection errorCollection) {
bool wasReload = reloading;
bool wasLoading = loadingDesigner;
// Set our state back to the starting point.
this.loadingDesigner = false;
this.reloading = false;
if (baseClassName != null) {
this.rootComponentClassName = baseClassName;
}
// If we had errors, report them.
//
if (successful && rootComponent == null) {
ArrayList errorList = new ArrayList();
errorList.Add(new Exception("No Base Class"));
errorCollection = errorList;
successful = false;
}
if (!successful) {
// The document is partially loaded. Unload it here.
try {
UnloadDocument();
}
catch (Exception ex) {
Debug.Fail("Failed to unload after a...failed load.", ex.ToString());
}
if (errorCollection != null) {
foreach(object errorObj in errorCollection) {
if (errorObj is Exception) {
loadError = (Exception)errorObj;
}
else {
loadError = new Exception(errorObj.ToString());
}
break;
}
}
else {
loadError = new Exception("Unknown Load Error");
}
documentWindow.SetDesigner(null);
}
else {
// We may be invoked to do an EndLoad when we are already loaded. This can happen
// if the user called AddLoadDependency, essentially putting us in a loading state
// while we are already loaded. This is OK, and is used as a hint that the user
// is going to monkey with settings but doesn't want the code engine to report
// it.
if (wasLoading) {
// and let everyone know that we're loaded
if (LoadComplete != null) {
LoadComplete(this, EventArgs.Empty);
}
}
}
documentWindow.ReportErrors(errorCollection);
documentWindow.DocumentVisible = true;
}
/// This is called by the designer loader when it wishes to reload the
/// design document. The reload may happen immediately or it may be deferred
/// until idle time. The designer loader should unload itself before calling
/// this method, to reset its state to that before BeginLoad was originally
/// called.
void IDesignerLoaderHost.Reload() {
// If the DesignerLoader has been destroyed already, then there
// is no need to reload
if (designerLoader == null || documentWindow == null) {
return;
}
// Before reloading, flush any changes!
designerLoader.Flush();
Cursor oldCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
ICollection selectedObjects = null;
ArrayList selectedNames = null;
IServiceProvider sp = (IServiceProvider)this;
ISelectionService selectionService = (ISelectionService)sp.GetService(typeof(ISelectionService));
if (selectionService != null) {
selectedObjects = selectionService.GetSelectedComponents();
selectedNames = new ArrayList();
foreach(object comp in selectedObjects) {
if (comp is IComponent && ((IComponent)comp).Site != null) {
selectedNames.Add(((IComponent)comp).Site.Name);
}
}
}
try {
UnloadDocument();
Load(true);
}
finally {
if (selectionService != null) {
ArrayList selection = new ArrayList();
foreach(string name in selectedNames) {
if (name != null) {
IComponent comp = ((IContainer)this).Components[name];
if (comp != null) {
selection.Add(comp);
}
}
}
selectionService.SetSelectedComponents(selection);
}
Cursor.Current = oldCursor;
}
}
//****
//****
//**** IDesignerHost Implementation
//****
//****
// Properties
public IContainer Container {
get {
return (IContainer)this;
}
}
// Gets a value indicating whether the designer host is currently in a transaction.
public bool InTransaction {
get {
return transactionCount > 0;
}
}
/// Is the document currently being loaded.
public bool Loading {
get {
return loadingDesigner || (designerLoader != null && designerLoader.Loading);
}
}
/// Retrieves the instance of the base class that is being used as the basis
/// for this design. This is typically a Form or UserControl instance; it
/// defines the class for which the user's derived class will extend.
public IComponent RootComponent {
get {
return rootComponent;
}
}
/// Retrieves the fully qualified name of the class that is being designed.
/// This class is not available at design time because it is the class that
/// is being designed, so the class's superclass is substituted. This allows
/// you to get at the fully qualified name of the class that will be used
/// at runtime.
public string RootComponentClassName {
get {
return rootComponentClassName;
}
}
// Gets the description of the current transaction.
public string TransactionDescription {
get {
if (transactionDescriptions != null) {
return transactionDescriptions.GetNonNull();
}
return "";
}
}
// Events
public event EventHandler Activated;
public event EventHandler Deactivated;
public event EventHandler LoadComplete;
public event DesignerTransactionCloseEventHandler TransactionClosed;
public event DesignerTransactionCloseEventHandler TransactionClosing;
public event EventHandler TransactionOpened;
public event EventHandler TransactionOpening;
// Methods
/// Causes the designer that this host is hosting to become activated.
public void Activate() {
documentWindow.Focus();
}
/// Creates a new component from the given class. A component name will be fabricated.
public IComponent CreateComponent(Type componentClass) {
string name = this.GetNewComponentName(componentClass);
return CreateComponent(componentClass, name);
}
public IComponent CreateComponent(Type componentClass, string name) {
object obj = null;
IComponent comp = null;
// Create the site we are going to use here so that our Container.Add implementation
// can pick it up - need to do this here because name is not passed to Container.Add
// by Foo(IContainer) constructor below.
newComponentSite = new SampleDesignSite(this,name);
// Create the Component - there are 2 possible ways to do this:
// Foo(IComponent) or Foo().
try {
// See if we can create the component using an IContainer constructor...
try {
object[] args = new object[] {this};
Type[] argTypes = new Type[] {typeof(IContainer)};
obj = CreateObject(componentClass, args, argTypes, false);
}
catch (Exception) {
}
// If it failed, try to create it with a default constructor
if (null == obj) {
obj = CreateObject(componentClass, null, null, false);
}
//Make sure we have a component
comp = obj as Component ;
if (comp == null) {
Exception ex = new Exception("The class is not a component " + componentClass.FullName);
throw ex;
}
// If we didn't have a constructor that took a Container or the site is not
// a SampleDesignSite the we will do the Container.Add() work
SampleDesignSite site = comp.Site as SampleDesignSite;
if (site == null) {
((IContainer)this).Add(comp);
}
// At this point, our add call should have used the new site we gave it (if there was
// one), and nulled out the holder pointer.
Debug.Assert(newComponentSite == null, "add didn't use newComponentSite");
}
catch (Exception) {
if (comp != null) {
try {
DestroyComponent(comp);
}
catch (Exception) {
}
}
throw;
}
if (comp != null)
{
AddDesignedComponent(comp);
}
return comp;
}
/// Lengthy operations that involve multiple components may raise many events. These events
/// may cause other side-effects, such as flicker or performance degradation. When operating
/// on multiple components at one time, or setting multiple properties on a single component,
/// you should encompass these changes inside a transaction. Transactions are used
/// to improve performance and reduce flicker. Slow operations can listen to
/// transaction events and only do work when the transaction completes.
public DesignerTransaction CreateTransaction() {
return CreateTransaction(null);
}
public DesignerTransaction CreateTransaction(string description) {
if (description == null) {
description = string.Empty;
}
return new SampleDesignerTransaction(this, description);
}
/// Destroys the given component, removing it from the design container.
public void DestroyComponent(IComponent comp) {
string name;
if (comp.Site != null && comp.Site.Name != null) {
name = comp.Site.Name;
}
else {
name = comp.GetType().Name;
}
// Make sure the component is not being inherited -- we can't delete these!
InheritanceAttribute ia = (InheritanceAttribute)TypeDescriptor.GetAttributes(comp)[typeof(InheritanceAttribute)];
if (ia != null && ia.InheritanceLevel != InheritanceLevel.NotInherited) {
throw new InvalidOperationException("CantDestroyInheritedComponent" + name);
}
DesignerTransaction t = null;
try {
// We try to remove the component from the container before destroying it.
t = CreateTransaction("DestroyComponentTransaction" + name);
// We need to signal changing and then perform the remove. Remove must be done by us and not
// by Dispose because (a) people need a chance to cancel through a Removing event, and (b)
// Dispose removes from the container last and anything that would sync Removed would end up
// with a dead component.
//
((IComponentChangeService)this).OnComponentChanging(comp, null);
if (comp.Site != null) {
Remove(comp);
}
DeleteDesignedComponent(comp);
comp.Dispose();
((IComponentChangeService)this).OnComponentChanged(comp, null, null, null);
}
finally {
if (t != null) {
t.Commit();
}
}
}
// Retrieves the designer for the given component.
public IDesigner GetDesigner(IComponent component) {
Debug.Assert(component != null, "Cannot call GetDesigner with a NULL component. Check that the root hasn't been disposed.");
if (component == null) throw new ArgumentNullException("component");
return(IDesigner)designerTable[component];
}
/// Retrieves the Type instance for the given type name. The type name must be
/// fully qualified, or it must be contained in an assembly that has been referenced
/// by the designer.
public Type GetType(string typeName) {
if (typeResolver == null) {
IServiceProvider sp = (IServiceProvider)this;
typeResolver = (ITypeResolutionService)sp.GetService(typeof(ITypeResolutionService));
}
if (typeResolver != null) {
return typeResolver.GetType(typeName);
}
return Type.GetType(typeName);
}
//****
//****
//**** IComponentChangeService Implementation
//****
//****
// Events
public event ComponentEventHandler ComponentAdded;
public event ComponentEventHandler ComponentAdding;
public event ComponentChangedEventHandler ComponentChanged;
public event ComponentChangingEventHandler ComponentChanging;
public event ComponentEventHandler ComponentRemoved;
public event ComponentEventHandler ComponentRemoving;
public event ComponentRenameEventHandler ComponentRename;
// Methods
/// This is called after a property has been changed. It allows
/// the implementor to do any post-processing that may be needed
/// after a property change. For example, a designer will typically
/// update the source code that sets the property with the new value.
void IComponentChangeService.OnComponentChanged(object component, MemberDescriptor member, object oldValue, object newValue) {
// If we're loading then eat changes. This just slows us down.
if (Loading) {
return;
}
if (ComponentChanged != null) {
ComponentChangedEventArgs ce = new ComponentChangedEventArgs(component, member, oldValue, newValue);
ComponentChanged(this, ce);
}
}
/// This is called when a property is about to change. Before the
/// property descriptor commits the property it will call this
/// method. This method should throw an exception if the property
/// cannot be changed. This is not intended to validate the values
/// of a particular property. Instead, it is intended to be a global
/// way of preventing a component from changing. For example, if
/// a designer file is checked into source code control, this would
/// typically throw an exception if the user refused to check out
/// the file.
void IComponentChangeService.OnComponentChanging(object component, MemberDescriptor member) {
// If we're loading then eat changes. This just slows us down.
if (Loading) {
if (member.Name == "Size")
{
string _DEBUG_ = member.Name;
}
return;
}
if (ComponentChanging != null) {
ComponentChangingEventArgs ce = new ComponentChangingEventArgs(component, member);
ComponentChanging(this, ce);
}
}
//****
//****
//**** IExtenderProviderService Implementation
//****
//****
// Methods
void IExtenderProviderService.AddExtenderProvider(IExtenderProvider provider) {
if (extenderProviders == null) {
extenderProviders = new ArrayList();
}
extenderProviders.Add(provider);
}
void IExtenderProviderService.RemoveExtenderProvider(IExtenderProvider provider) {
if (extenderProviders != null) {
extenderProviders.Remove(provider);
}
}
//****
//****
//**** Sample Designer Host methods
//****
//****
/// Validates that the given name is OK to use. Not only does it have to
/// be a valid identifier, but it must not already be in our container.
internal void CheckName(string name) {
if (name == null || name.Length == 0) {
Exception ex = new Exception("Components must have a name");
throw ex;
}
if (((IContainer)this).Components[name] != null) {
Exception ex = new Exception("We already have a component named " + name);
throw ex;
}
if (nameService == null) {
IServiceProvider sp = (IServiceProvider)this;
nameService = (INameCreationService)sp.GetService(typeof(INameCreationService));
}
if (nameService != null) {
nameService.ValidateName(name);
}
}
private void CreateComponentDesigner(IComponent component) {
// Is this the first component the loader has created? If so, then it must
// be the base component (by definition) so we will expect there to be a document
// designer associated with the component. Otherwise, we search for a
// normal designer, which can be optionally provided.
IDesigner designer = null;
if (rootComponent == null) {
rootComponent = component;
// Get the root designer. We check right here to see if the document window supports
// hosting this type of designer. If not, we bail early.
rootDesigner = (IRootDesigner)TypeDescriptor.CreateDesigner(component, typeof(IRootDesigner));
if (rootDesigner == null) {
rootComponent = null;
Exception ex = new Exception("No Top Level Designer for " + component.GetType().FullName);
throw ex;
}
ViewTechnology[] technologies = rootDesigner.SupportedTechnologies;
bool supported = false;
foreach(ViewTechnology tech in technologies) {
if (tech == ViewTechnology.WindowsForms) {
supported = true;
break;
}
}
if (!supported) {
Exception ex = new Exception("This designer host does not support the designer for " + component.GetType().FullName);
throw ex;
}
designer = rootDesigner;
// Check and see if anyone has set the class name of the base component.
// We default to the component name.
if (rootComponentClassName == null) {
rootComponentClassName = component.Site.Name;
}
}
else {
designer = TypeDescriptor.CreateDesigner(component, typeof(IDesigner));
}
if (designer != null) {
designerTable[component] = designer;
try {
designer.Initialize(component);
}
catch {
designerTable.Remove(component);
if (designer == rootDesigner) {
rootDesigner = null;
}
throw;
}
if (designer is IExtenderProvider &&
!TypeDescriptor.GetAttributes(designer).Contains(InheritanceAttribute.InheritedReadOnly)) {
((IExtenderProviderService)this).AddExtenderProvider((IExtenderProvider)designer);
}
// Now, if this is the root designer, initialize the designer window with it.
if (designer == rootDesigner) {
documentWindow.SetDesigner(rootDesigner);
}
}
}
/// Create an instance of a type given arguments and their types.
private object CreateObject(Type objectClass, object []args, Type[] argTypes, bool fThrowException) {
ConstructorInfo ctr = null;
if (args != null && args.Length > 0) {
if (argTypes == null) {
argTypes = new Type[args.Length];
for (int i = args.Length - 1; i>= 0; i--) {
if (args[i] != null) argTypes[i] = args[i].GetType();
}
}
ctr = objectClass.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null);
if (ctr == null && fThrowException) {
Exception ex = new Exception("Cannot find a constructor with the right arguments for " + objectClass.FullName);
throw ex;
}
else
return null;
}
try {
return(ctr == null) ? Activator.CreateInstance(objectClass) : ctr.Invoke(args);
}
catch (Exception e) {
if (e is TargetInvocationException) {
e = e.InnerException;
}
string message = e.Message;
if (message == null) {
message = e.ToString();
}
throw new Exception( "Cannot create an instance of "
+ objectClass.FullName
+ " because " + e.ToString(), e);
}
}
/// Create a name from a new component of a given type.
internal string GetNewComponentName(Type compClass) {
IServiceProvider sp = (IServiceProvider)this;
INameCreationService nameCreate = (INameCreationService)sp.GetService(typeof(INameCreationService));
if (nameCreate != null) {
return nameCreate.CreateName(Container, compClass);
}
// Do a default thing...
//
string baseName = compClass.Name;
// Camel case the base name.
//
StringBuilder b = new StringBuilder(baseName.Length);
for (int i = 0; i < baseName.Length; i++) {
if (Char.IsUpper(baseName[i]) && (i == 0 || i == baseName.Length - 1 || Char.IsUpper(baseName[i+1]))) {
b.Append(Char.ToLower(baseName[i]));
}
else {
b.Append(baseName.Substring(i));
break;
}
}
baseName = b.ToString();
int idx = 1;
string finalName = baseName + idx.ToString();
while(Container.Components[finalName] != null) {
idx++;
finalName = baseName + idx.ToString();
}
return finalName;
}
/// Loads the design document using the DesignerLoader
private void Load(bool reloading) {
Cursor oldCursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
this.reloading = reloading;
try {
if (!reloading && designerLoader is IExtenderProvider) {
((IExtenderProviderService)this).AddExtenderProvider((IExtenderProvider)designerLoader);
}
loadingDesigner = true;
loadError = null;
designerLoader.BeginLoad(this);
}
catch (Exception e) {
Exception exNew = e;
if (e is TargetInvocationException) {
exNew = e.InnerException;
}
string message = exNew.Message;
// We must handle the case of an exception with no message.
if (message == null || message.Length == 0) {
Debug.Fail("Parser has thrown an exception that has no friendly message", exNew.ToString());
exNew = new Exception("Parser has thrown an exception that has no friendly message" + exNew.ToString());
}
// Loader blew up. Add this exception to our error list
ArrayList errorList = new ArrayList();
errorList.Add(exNew);
((IDesignerLoaderHost)this).EndLoad(null, false, errorList);
}
Cursor.Current = oldCursor;
}
/// Load the contents of the designer
public void LoadDocument(DesignerLoader designerLoader) {
try {
this.designerLoader = designerLoader;
// Create the Design View
documentWindow = new SampleDocumentWindow(this);
// Load the document
Load(false);
}
catch (Exception t) {
Debug.Fail(t.ToString());
throw;
}
}
/// This is called after a component has been added to the container.
private void OnComponentAdded(ComponentEventArgs ce) {
if (ComponentAdded != null) {
// This is just to double-check that our TypeResolutionService has the
// necessary assemblies in its internal set. After all, compilation depends
// on it! Normally our ToolboxItems do this for us, but if we open an XML
// document and load it, we get no help from the ToolboxItems.
//
ITypeResolutionService trs = ((IServiceContainer)this).GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;
trs.ReferenceAssembly(ce.Component.GetType().Assembly.GetName());
ComponentAdded(this, ce);
}
}
/// This is called when a component is about to be added to our container.
private void OnComponentAdding(ComponentEventArgs ce) {
if (ComponentAdding != null) {
ComponentAdding(this, ce);
}
}
/// This is called after a component has been removed from the container, but before
/// the component's site has been destroyed.
private void OnComponentRemoved(ComponentEventArgs ce) {
if (ComponentRemoved != null) {
ComponentRemoved(this, ce);
}
}
/// This is called when a component is about to be removed from our container.
private void OnComponentRemoving(ComponentEventArgs ce) {
if (ComponentRemoving != null) {
ComponentRemoving(this, ce);
}
}
/// This is called when a component has been renamed.
internal void OnComponentRename(ComponentRenameEventArgs ce) {
if (ComponentRename != null) {
ComponentRename(this, ce);
}
}
/// Creates some of the more infrequently used services
private object OnCreateService(IServiceContainer container, Type serviceType) {
// Create SelectionService
if (serviceType == typeof(ISelectionService)) {
if (selectionService == null) {
selectionService = new SampleSelectionService(this);
}
return selectionService;
}
if (serviceType == typeof(ITypeDescriptorFilterService)) {
return new SampleTypeDescriptorFilterService(this);
}
if (serviceType == typeof(IToolboxService)) {
if (toolboxService == null) {
toolboxService = new SampleToolboxService(this);
}
return toolboxService;
}
if (serviceType == typeof(IMenuCommandService)) {
if (menuCommandService == null) {
menuCommandService = new SampleMenuCommandService(this);
}
return menuCommandService;
}
// UNIMPLEMENTED
// if (serviceType == typeof(IHelpService)) {
// if (helpService == null) {
// helpService = new SampleHelpService(this);
// }
// return helpService;
// }
//
// if (serviceType == typeof(IReferenceService)) {
// if (referenceService == null) {
// referenceService = new SampleReferenceService(this, true);
// }
// return referenceService;
// }
//
// if (serviceType == typeof(IPropertyValueUIService)) {
// return new SamplePropertyValueUIService();
// }
//
// if (serviceType == typeof(IMenuEditorService)) {
// if (menuEditorService == null) {
// menuEditorService = new SampleMenuEditorService(this);
// }
// return menuEditorService;
// }
if (serviceType == typeof(IDesignerSerializationService))
{
if (serializationService == null)
{
serializationService = new SampleDesignerSerializationService(this);
}
return serializationService;
}
Debug.Fail("Service type " + serviceType.FullName + " requested but we don't support it");
return null;
}
internal void OnTransactionOpened(EventArgs e) {
if (TransactionOpened != null)
TransactionOpened(this, e);
}
internal void OnTransactionOpening(EventArgs e) {
if (TransactionOpening != null)
TransactionOpening(this, e);
}
internal void OnTransactionClosed(DesignerTransactionCloseEventArgs e) {
if (TransactionClosed != null)
TransactionClosed(this, e);
}
internal void OnTransactionClosing(DesignerTransactionCloseEventArgs e) {
if (TransactionClosing != null)
TransactionClosing(this, e);
}
/// Called to remove a component from its container.
private void Remove(IComponent component) {
// Bail early if this component hasn't been added to us.
if (component == null) return;
ISite site = component.Site;
if (!sites.ContainsValue(site)) return;
if (site == null || site.Container != this) return;
if (!(site is SampleDesignSite)) return;
ComponentEventArgs ce = new ComponentEventArgs(component);
OnComponentRemoving(ce);
// Remove the component from extender provider list if its an extender provider
SampleDesignSite csite = (SampleDesignSite)site;
if (csite.Component != rootComponent) {
if (component is IExtenderProvider) {
((IExtenderProviderService)this).RemoveExtenderProvider((IExtenderProvider)component);
}
}
// and remove it's designer, should one exist.
IDesigner designer = (IDesigner)designerTable[component];
if (designer != null) {
designer.Dispose();
}
designerTable.Remove(component);
sites.Remove(csite.Name);
if (components != null) {
components.Remove(site);
}
// By this time, the component is dead. If some bonehead
// threw, there's nothing we can do about it.
//
try {
OnComponentRemoved(ce);
}
catch (Exception) {
}
// Finally, rip the site instance.
component.Site = null;
}
// Exposed to allow ancillary classes to access this internal state.
internal Hashtable Sites {
get {
return sites;
}
}
// Get descriptions of all of our transactions.
internal StringStack TransactionDescriptions {
get {
if (transactionDescriptions == null) {
transactionDescriptions = new StringStack();
}
return transactionDescriptions;
}
}
// Get or set the number of transactions we have.
internal int TransactionCount {
get {
return transactionCount;
}
set {
transactionCount = value ;
}
}
// This is called during Dispose and Reload methods to unload the current designer.
private void UnloadDocument() {
if (helpService != null && rootDesigner != null) {
helpService.RemoveContextAttribute("Keyword", "Designer_" + rootDesigner.GetType().FullName);
}
// Note: Because this can be called during Dispose, we are very anal here
// about checking for null references.
// If we can get a selection service, clear the selection...
// we don't want the property browser browsing disposed components...
// or components who's designer has been destroyed.
IServiceProvider sp = (IServiceProvider)this;
ISelectionService selectionService = (ISelectionService)sp.GetService(typeof(ISelectionService));
Debug.Assert(selectionService != null, "ISelectionService not found");
if (selectionService != null) {
selectionService.SetSelectedComponents(null);
}
// Stash off the base designer and component. We are
// going to be destroying these and we don't want them
// to be accidently referenced after they're dead.
//
IDesigner rootDesignerHolder = rootDesigner;
IComponent rootComponentHolder = rootComponent;
rootDesigner = null;
rootComponent = null;
rootComponentClassName = null;
SampleDesignSite[] siteArray = new SampleDesignSite[sites.Values.Count];
sites.Values.CopyTo(siteArray, 0);
// Destroy all designers. We save the base designer for last.
//
IDesigner[] designers = new IDesigner[designerTable.Values.Count];
designerTable.Values.CopyTo(designers, 0);
designerTable.Clear();
// Loading, unloading, it's all the same. It indicates that you
// shouldn't dirty or otherwise mess with the buffer. We also
// create a transaction here to limit the effects of making
// so many changes.
loadingDesigner = true;
DesignerTransaction trans = CreateTransaction();
try {
for (int i = 0; i < designers.Length; i++) {
if (designers[i] != rootDesignerHolder) {
try {
designers[i].Dispose();
}
catch {
Debug.Fail("Designer " + designers[i].GetType().Name + " threw an exception during Dispose.");
}
}
}
// Now destroy all components.
for (int i = 0; i < siteArray.Length; i++) {
SampleDesignSite site = siteArray[i];
IComponent comp = site.Component;
if (comp != null && comp != rootComponentHolder) {
try {
comp.Dispose();
}
catch {
Debug.Fail("Component " + site.Name + " threw during dispose. Bad component!!");
}
if (comp.Site != null) {
Debug.Fail("Component " + site.Name + " did not remove itself from its container");
Remove(comp);
}
}
}
// Finally, do the base designer and component.
//
if (rootDesignerHolder != null) {
try {
rootDesignerHolder.Dispose();
}
catch {
Debug.Fail("Designer " + rootDesignerHolder.GetType().Name + " threw an exception during Dispose.");
}
}
if (rootComponentHolder != null) {
try {
rootComponentHolder.Dispose();
}
catch {
Debug.Fail("Component " + rootComponentHolder.GetType().Name + " threw during dispose. Bad component!!");
}
if (rootComponentHolder.Site != null) {
Debug.Fail("Component " + rootComponentHolder.Site.Name + " did not remove itself from its container");
Remove(rootComponentHolder);
}
}
sites.Clear();
if (components != null) {
components.Clear();
}
}
finally {
loadingDesigner = false;
trans.Commit();
}
// And clear the document window
//
if (documentWindow != null) {
documentWindow.SetDesigner(null);
}
}
//Return the designer control.
public Control View {
get {
return documentWindow;
}
}
/// The IDesignerEventService is responsible for designer events. Since we have only
/// our one designer host, we always return it when asked for the ActiveDesigner or
/// Designers.
#region Implementation of IDesignerEventService
public DesignerCollection Designers
{
get
{
return new DesignerCollection(new IDesignerHost[] { this });
}
}
public event System.ComponentModel.Design.DesignerEventHandler DesignerDisposed;
public IDesignerHost ActiveDesigner
{
get
{
return this;
}
}
public event System.ComponentModel.Design.DesignerEventHandler DesignerCreated;
public event System.ComponentModel.Design.ActiveDesignerEventHandler ActiveDesignerChanged;
public event System.EventHandler SelectionChanged;
#endregion
//public void ChangeSelectionExecute(object sender, EventArgs e)
//{
// throw new Exception();
//
//}
// START OF ADD TO SampleDesignerHost
private IDesignerSerializationService serializationService; // service de serialisation
// +Add for the copy function
internal void WriteComponentCollection(System.Xml.XmlDocument document, IList list, System.Xml.XmlNode parent)
{
((SampleDesignerLoader)designerLoader).WriteComponentCollection(document, list, parent);
}
internal ICollection CreateComponents(System.Xml.XmlDocument xSource, ArrayList errors)
{
return ((SampleDesignerLoader)designerLoader).CreateComponents(xSource, errors);
}
// -Add for the copy function
// END OF ADD TO SampleDesignerHost
public void HideCombo()
{
currentComponentsCombo.Visible = false;
currentComponentsCombo.Parent = null;
//savedComponentItems = VisualPascalABC.Form1.Form1_object.PropertiesWindow.componentItems;
//savedItemsComponent = VisualPascalABC.Form1.Form1_object.PropertiesWindow.itemsComponent;
//NETXP.Controls.ComboBoxExItemCollection c = VisualPascalABC.Form1.Form1_object.PropertiesWindow.GetItemsControls();
//savedAllComponents = new NETXP.Controls.ComboBoxExItem[c.Count];
//if (c.Count > 0)
//{
// c.CopyTo(savedAllComponents, 0);
//}
}
public void ShowCombo()
{
Panel p = VisualPascalABC.Form1.Form1_object.PropertiesWindow.GetComponentsComboPanel();
currentComponentsCombo.Parent = p;
currentComponentsCombo.Visible = true;
//VisualPascalABC.Form1.Form1_object.PropertiesWindow.componentItems = savedComponentItems;
//VisualPascalABC.Form1.Form1_object.PropertiesWindow.itemsComponent = savedItemsComponent;
//NETXP.Controls.ComboBoxExItemCollection c = VisualPascalABC.Form1.Form1_object.PropertiesWindow.GetItemsControls();
//c.Clear();
//c.AddRange(savedAllComponents);
}
}
}