536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
393 lines
15 KiB
C#
393 lines
15 KiB
C#
namespace System.Workflow.ComponentModel.Design
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Globalization;
|
|
|
|
internal sealed class ReferenceService : IReferenceService, IDisposable
|
|
{
|
|
private static readonly Attribute[] Attributes = new Attribute[] { BrowsableAttribute.Yes };
|
|
private IServiceProvider provider; // service provider we use to get to other services
|
|
private ArrayList addedComponents; // list of newly added components
|
|
private ArrayList removedComponents; // list of newly removed components
|
|
private ArrayList changedComponents; // list of changed components, we will re-cylcle their references too
|
|
private ArrayList references; // our current list of references
|
|
|
|
internal ReferenceService(IServiceProvider provider)
|
|
{
|
|
this.provider = provider;
|
|
}
|
|
|
|
~ReferenceService()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
private void CreateReferences(IComponent component)
|
|
{
|
|
CreateReferences(string.Empty, component, component);
|
|
}
|
|
|
|
private void CreateReferences(string trailingName, object reference, IComponent sitedComponent)
|
|
{
|
|
if (object.ReferenceEquals(reference, null))
|
|
return;
|
|
|
|
this.references.Add(new ReferenceHolder(trailingName, reference, sitedComponent));
|
|
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(reference, Attributes))
|
|
{
|
|
object value = null;
|
|
try
|
|
{
|
|
value = property.GetValue(reference);
|
|
}
|
|
catch
|
|
{
|
|
// Work around!!! if an property getter throws exception then we ignore it.
|
|
}
|
|
if (value != null)
|
|
{
|
|
BrowsableAttribute[] browsableAttrs = (BrowsableAttribute[])(value.GetType().GetCustomAttributes(typeof(BrowsableAttribute), true));
|
|
if (browsableAttrs.Length > 0 && browsableAttrs[0].Browsable)
|
|
{
|
|
CreateReferences(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[] { trailingName, property.Name }), property.GetValue(reference), sitedComponent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureReferences()
|
|
{
|
|
// If the references are null, create them for the first time and connect
|
|
// up our events to listen to changes to the container. Otherwise, check to
|
|
// see if the added or removed lists contain anything for us to sync up.
|
|
//
|
|
if (this.references == null)
|
|
{
|
|
if (this.provider == null)
|
|
{
|
|
throw new ObjectDisposedException("IReferenceService");
|
|
}
|
|
|
|
IComponentChangeService cs = this.provider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
|
Debug.Assert(cs != null, "Reference service relies on IComponentChangeService");
|
|
if (cs != null)
|
|
{
|
|
cs.ComponentAdded += new ComponentEventHandler(this.OnComponentAdded);
|
|
cs.ComponentRemoved += new ComponentEventHandler(this.OnComponentRemoved);
|
|
cs.ComponentRename += new ComponentRenameEventHandler(this.OnComponentRename);
|
|
cs.ComponentChanged += new ComponentChangedEventHandler(this.OnComponentChanged);
|
|
}
|
|
|
|
TypeDescriptor.Refreshed += new RefreshEventHandler(OnComponentRefreshed);
|
|
|
|
IContainer container = this.provider.GetService(typeof(IContainer)) as IContainer;
|
|
if (container == null)
|
|
{
|
|
Debug.Fail("Reference service cannot operate without IContainer");
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
this.references = new ArrayList(container.Components.Count);
|
|
|
|
foreach (IComponent component in container.Components)
|
|
{
|
|
CreateReferences(component);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (this.addedComponents != null && this.addedComponents.Count > 0)
|
|
{
|
|
// There is a possibility that this component already exists.
|
|
// If it does, just remove it first and then re-add it.
|
|
//
|
|
ArrayList clonedAddedComponents = new ArrayList(this.addedComponents);
|
|
foreach (IComponent ic in clonedAddedComponents)
|
|
{
|
|
RemoveReferences(ic);
|
|
CreateReferences(ic);
|
|
}
|
|
this.addedComponents.Clear();
|
|
}
|
|
|
|
if (this.removedComponents != null && this.removedComponents.Count > 0)
|
|
{
|
|
ArrayList clonedRemovedComponents = new ArrayList(this.removedComponents);
|
|
foreach (IComponent ic in clonedRemovedComponents)
|
|
RemoveReferences(ic);
|
|
|
|
this.removedComponents.Clear();
|
|
}
|
|
if (this.changedComponents != null && this.changedComponents.Count > 0)
|
|
{
|
|
ArrayList clonedChangedComponents = new ArrayList(this.changedComponents);
|
|
foreach (IComponent ic in clonedChangedComponents)
|
|
{
|
|
RemoveReferences(ic);
|
|
CreateReferences(ic);
|
|
}
|
|
this.changedComponents.Clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnComponentChanged(object sender, ComponentChangedEventArgs cevent)
|
|
{
|
|
IComponent comp = ((IReferenceService)this).GetComponent(cevent.Component);
|
|
|
|
if (comp != null)
|
|
{
|
|
if ((this.addedComponents == null || !this.addedComponents.Contains(comp)) &&
|
|
(this.removedComponents == null || !this.removedComponents.Contains(comp)))
|
|
{
|
|
if (this.changedComponents == null)
|
|
{
|
|
this.changedComponents = new ArrayList();
|
|
this.changedComponents.Add(comp);
|
|
}
|
|
else if (!this.changedComponents.Contains(comp))
|
|
{
|
|
this.changedComponents.Add(comp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnComponentAdded(object sender, ComponentEventArgs cevent)
|
|
{
|
|
if (this.addedComponents == null)
|
|
this.addedComponents = new ArrayList();
|
|
this.addedComponents.Add(cevent.Component);
|
|
if (this.removedComponents != null)
|
|
this.removedComponents.Remove(cevent.Component);
|
|
if (this.changedComponents != null)
|
|
this.changedComponents.Remove(cevent.Component);
|
|
}
|
|
|
|
private void OnComponentRemoved(object sender, ComponentEventArgs cevent)
|
|
{
|
|
if (this.removedComponents == null)
|
|
this.removedComponents = new ArrayList();
|
|
|
|
this.removedComponents.Add(cevent.Component);
|
|
|
|
if (this.addedComponents != null)
|
|
this.addedComponents.Remove(cevent.Component);
|
|
if (this.changedComponents != null)
|
|
this.changedComponents.Remove(cevent.Component);
|
|
}
|
|
|
|
private void OnComponentRename(object sender, ComponentRenameEventArgs cevent)
|
|
{
|
|
foreach (ReferenceHolder reference in this.references)
|
|
{
|
|
if (object.ReferenceEquals(reference.SitedComponent, cevent.Component))
|
|
{
|
|
reference.ResetName();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
private void OnComponentRefreshed(RefreshEventArgs e)
|
|
{
|
|
if (e.ComponentChanged != null)
|
|
OnComponentChanged(this, new ComponentChangedEventArgs(e.ComponentChanged, null, null, null));
|
|
}
|
|
|
|
private void RemoveReferences(IComponent component)
|
|
{
|
|
if (this.references != null)
|
|
{
|
|
int size = this.references.Count;
|
|
for (int i = size - 1; i >= 0; i--)
|
|
{
|
|
if (object.ReferenceEquals(((ReferenceHolder)this.references[i]).SitedComponent, component))
|
|
this.references.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
private void Dispose(bool disposing)
|
|
{
|
|
if (this.references != null && this.provider != null)
|
|
{
|
|
IComponentChangeService cs = this.provider.GetService(typeof(IComponentChangeService)) as IComponentChangeService;
|
|
if (cs != null)
|
|
{
|
|
cs.ComponentAdded -= new ComponentEventHandler(this.OnComponentAdded);
|
|
cs.ComponentRemoved -= new ComponentEventHandler(this.OnComponentRemoved);
|
|
cs.ComponentRename -= new ComponentRenameEventHandler(this.OnComponentRename);
|
|
cs.ComponentChanged -= new ComponentChangedEventHandler(this.OnComponentChanged);
|
|
}
|
|
|
|
TypeDescriptor.Refreshed -= new RefreshEventHandler(OnComponentRefreshed);
|
|
|
|
this.references = null;
|
|
this.provider = null;
|
|
}
|
|
}
|
|
|
|
IComponent IReferenceService.GetComponent(object reference)
|
|
{
|
|
if (object.ReferenceEquals(reference, null))
|
|
throw new ArgumentNullException("reference");
|
|
|
|
EnsureReferences();
|
|
|
|
foreach (ReferenceHolder holder in this.references)
|
|
{
|
|
if (object.ReferenceEquals(holder.Reference, reference))
|
|
return holder.SitedComponent;
|
|
}
|
|
return null;
|
|
}
|
|
string IReferenceService.GetName(object reference)
|
|
{
|
|
if (object.ReferenceEquals(reference, null))
|
|
throw new ArgumentNullException("reference");
|
|
|
|
EnsureReferences();
|
|
|
|
foreach (ReferenceHolder holder in this.references)
|
|
{
|
|
if (object.ReferenceEquals(holder.Reference, reference))
|
|
return holder.Name;
|
|
}
|
|
return null;
|
|
}
|
|
object IReferenceService.GetReference(string name)
|
|
{
|
|
if (name == null)
|
|
throw new ArgumentNullException("name");
|
|
|
|
EnsureReferences();
|
|
|
|
foreach (ReferenceHolder holder in this.references)
|
|
{
|
|
if (string.Equals(holder.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
return holder.Reference;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
object[] IReferenceService.GetReferences()
|
|
{
|
|
EnsureReferences();
|
|
|
|
object[] references = new object[this.references.Count];
|
|
for (int i = 0; i < references.Length; i++)
|
|
references[i] = ((ReferenceHolder)this.references[i]).Reference;
|
|
|
|
return references;
|
|
}
|
|
|
|
object[] IReferenceService.GetReferences(Type baseType)
|
|
{
|
|
if (baseType == null)
|
|
throw new ArgumentNullException("baseType");
|
|
|
|
EnsureReferences();
|
|
|
|
ArrayList results = new ArrayList(this.references.Count);
|
|
foreach (ReferenceHolder holder in this.references)
|
|
{
|
|
object reference = holder.Reference;
|
|
if (baseType.IsAssignableFrom(reference.GetType()))
|
|
results.Add(reference);
|
|
}
|
|
|
|
object[] references = new object[results.Count];
|
|
results.CopyTo(references, 0);
|
|
return references;
|
|
}
|
|
|
|
private sealed class ReferenceHolder
|
|
{
|
|
private string trailingName;
|
|
private object reference;
|
|
private IComponent sitedComponent;
|
|
private string fullName;
|
|
|
|
internal ReferenceHolder(string trailingName, object reference, IComponent sitedComponent)
|
|
{
|
|
this.trailingName = trailingName;
|
|
this.reference = reference;
|
|
this.sitedComponent = sitedComponent;
|
|
|
|
Debug.Assert(trailingName != null, "Expected a trailing name");
|
|
Debug.Assert(reference != null, "Expected a reference");
|
|
|
|
#if DEBUG
|
|
|
|
Debug.Assert(sitedComponent != null, "Expected a sited component");
|
|
if (sitedComponent != null)
|
|
Debug.Assert(sitedComponent.Site != null, "Sited component is not really sited: " + sitedComponent.ToString());
|
|
if (sitedComponent != null && sitedComponent.Site != null)
|
|
Debug.Assert(sitedComponent.Site.Name != null, "Sited component has no name: " + sitedComponent.ToString());
|
|
|
|
#endif // DEBUG
|
|
}
|
|
|
|
internal void ResetName()
|
|
{
|
|
this.fullName = null;
|
|
}
|
|
|
|
internal string Name
|
|
{
|
|
get
|
|
{
|
|
if (this.fullName == null)
|
|
{
|
|
if (this.sitedComponent != null && this.sitedComponent.Site != null && this.sitedComponent.Site.Name != null)
|
|
{
|
|
this.fullName = string.Format(CultureInfo.InvariantCulture, "{0}{1}", new object[] { this.sitedComponent.Site.Name, this.trailingName });
|
|
}
|
|
else
|
|
{
|
|
#if DEBUG
|
|
Debug.Assert(this.sitedComponent != null, "Expected a sited component");
|
|
if (this.sitedComponent != null)
|
|
Debug.Assert(this.sitedComponent.Site != null, "Sited component is not really sited: " + this.sitedComponent.ToString());
|
|
if (this.sitedComponent != null && this.sitedComponent.Site != null)
|
|
Debug.Assert(this.sitedComponent.Site.Name != null, "Sited component has no name: " + this.sitedComponent.ToString());
|
|
#endif // DEBUG
|
|
this.fullName = string.Empty;
|
|
}
|
|
}
|
|
return this.fullName;
|
|
}
|
|
}
|
|
|
|
internal object Reference
|
|
{
|
|
get
|
|
{
|
|
return this.reference;
|
|
}
|
|
}
|
|
|
|
internal IComponent SitedComponent
|
|
{
|
|
get
|
|
{
|
|
return this.sitedComponent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|