Browse Source

Work on designer extensibility framework.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2224 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
f890f57886
  1. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs
  2. 23
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs
  3. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs
  4. 6
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
  5. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
  6. 3
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
  7. 8
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs
  8. 73
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
  9. 79
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs
  10. 7
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs
  11. 56
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionForAttribute.cs
  12. 190
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs
  13. 78
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServer.cs
  14. 42
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServerAttribute.cs
  15. 16
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/HashSet.cs
  16. 23
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Linq.cs
  17. 56
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs
  18. 9
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

1
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs

@ -7,6 +7,7 @@ using System.Resources; @@ -7,6 +7,7 @@ using System.Resources;
using System.Globalization;
using System.Windows;
using System.Runtime.InteropServices;
using ICSharpCode.WpfDesign.Extensions;
#endregion

23
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Windows;
using System.Windows.Controls;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign.Designer.Extensions
{
/// <summary>
/// Makes the TabItem clickable.
/// </summary>
[ExtensionFor(typeof(TabItem))]
public sealed class TabItemClickableExtension : BehaviorExtension
{
}
}

1
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs

@ -10,6 +10,7 @@ using System.Collections.Generic; @@ -10,6 +10,7 @@ using System.Collections.Generic;
namespace ICSharpCode.WpfDesign.Designer
{
// Static helpers that should become extension methods in the future
static class Linq
{
public static T[] ToArray<T>(ICollection<T> collection)

6
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs

@ -50,11 +50,11 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -50,11 +50,11 @@ namespace ICSharpCode.WpfDesign.Designer.Services
public void OnMouseDown(IDesignPanel designPanel, MouseButtonEventArgs e)
{
e.Handled = true;
new SelectionTask().Start(designPanel, e);
new SelectionGesture().Start(designPanel, e);
}
}
abstract class TaskBase
abstract class MouseGestureBase
{
protected IDesignPanel designPanel;
bool isStarted;
@ -120,7 +120,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services @@ -120,7 +120,7 @@ namespace ICSharpCode.WpfDesign.Designer.Services
protected virtual void OnStopped() {}
}
sealed class SelectionTask : TaskBase
sealed class SelectionGesture : MouseGestureBase
{
protected override void OnStarted(MouseButtonEventArgs e)
{

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj

@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="Controls\SingleVisualChildElement.cs" />
<Compile Include="DesignPanel.cs" />
<Compile Include="HashSet.cs" />
<Compile Include="Extensions\TabItemClickableExtension.cs" />
<Compile Include="Linq.cs" />
<Compile Include="ServiceRequiredException.cs" />
<Compile Include="Services\SelectionService.cs" />
@ -72,6 +72,7 @@ @@ -72,6 +72,7 @@
<ItemGroup>
<Folder Include="Configuration" />
<Folder Include="Controls" />
<Folder Include="Extensions" />
<Folder Include="Xaml" />
<Folder Include="Services" />
<ProjectReference Include="..\..\WpfDesign.XamlDom\Project\WpfDesign.XamlDom.csproj">

3
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs

@ -30,6 +30,9 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml @@ -30,6 +30,9 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml
_componentService = new XamlComponentService(this);
this.Services.AddService(typeof(IComponentService), _componentService);
// register extensions from this assembly:
this.Services.ExtensionManager.RegisterAssembly(typeof(XamlDesignContext).Assembly);
_rootItem = _componentService.RegisterXamlComponentRecursive(doc.RootElement);
}

8
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs

@ -18,6 +18,14 @@ namespace ICSharpCode.WpfDesign @@ -18,6 +18,14 @@ namespace ICSharpCode.WpfDesign
{
readonly ServiceContainer _services = new ServiceContainer();
/// <summary>
/// Creates a new DesignContext instance.
/// </summary>
protected DesignContext()
{
_services.AddService(typeof(Extensions.ExtensionManager), new Extensions.ExtensionManager(this));
}
/// <summary>
/// Gets the <see cref="ServiceContainer"/>.
/// </summary>

73
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs

@ -9,6 +9,7 @@ using System; @@ -9,6 +9,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using ICSharpCode.WpfDesign.Extensions;
namespace ICSharpCode.WpfDesign
{
@ -16,11 +17,6 @@ namespace ICSharpCode.WpfDesign @@ -16,11 +17,6 @@ namespace ICSharpCode.WpfDesign
/// The DesignItem connects a component with the service system and the designers.
/// Equivalent to Cider's ModelItem.
/// </summary>
/// <remarks>
/// About the Cider extension system:
/// http://blogs.msdn.com/jnak/archive/2006/04/24/580393.aspx
/// http://blogs.msdn.com/jnak/archive/2006/08/04/687166.aspx
/// </remarks>
public abstract class DesignItem
{
/// <summary>
@ -45,5 +41,72 @@ namespace ICSharpCode.WpfDesign @@ -45,5 +41,72 @@ namespace ICSharpCode.WpfDesign
[DebuggerStepThrough]
get { return this.Context.Services; }
}
#region Extensions support
private struct ExtensionEntry
{
internal readonly Extension Extension;
internal readonly ExtensionServer Server;
public ExtensionEntry(Extension extension, ExtensionServer server)
{
this.Extension = extension;
this.Server = server;
}
}
ExtensionServer[] _extensionServers;
bool[] _extensionServerIsApplied;
List<ExtensionEntry> _extensions = new List<ExtensionEntry>();
/// <summary>
/// Gets the extensions registered for this DesignItem.
/// </summary>
public IEnumerable<Extension> Extensions {
get {
foreach (ExtensionEntry entry in _extensions) {
yield return entry.Extension;
}
}
}
internal void SetExtensionServers(ExtensionServer[] extensionServers)
{
Debug.Assert(_extensionServers == null);
Debug.Assert(extensionServers != null);
_extensionServers = extensionServers;
_extensionServerIsApplied = new bool[extensionServers.Length];
}
internal void ApplyExtensions(ExtensionManager extensionManager)
{
Debug.Assert(_extensionServers != null);
for (int i = 0; i < _extensionServers.Length; i++) {
bool shouldApply = _extensionServers[i].ShouldApplyExtensions(this);
if (shouldApply != _extensionServerIsApplied[i]) {
ExtensionServer server = _extensionServers[i];
if (shouldApply) {
// add extensions
foreach (Extension ext in extensionManager.CreateExtensions(server, this)) {
_extensions.Add(new ExtensionEntry(ext, server));
}
} else {
// remove extensions
_extensions.RemoveAll(
delegate (ExtensionEntry entry) {
if (entry.Server == server) {
server.RemoveExtension(entry.Extension);
return true;
} else {
return false;
}
});
}
}
}
}
#endregion
}
}

79
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Base class for extensions that provide a behavior interface for the designed item.
/// These extensions are always loaded. They must have an parameter-less constructor.
/// </summary>
[ExtensionServer(typeof(BehaviorExtension.BehaviorExtensionServer))]
public abstract class BehaviorExtension : Extension
{
DesignItem _extendedItem;
/// <summary>
/// Gets the item that is being extended by the BehaviorExtension.
/// </summary>
public DesignItem ExtendedItem {
get {
if (_extendedItem == null)
throw new InvalidOperationException("Cannot access BehaviorExtension.ExtendedItem: " +
"The property is not initialized yet. Please move initialization logic " +
"that depends on ExtendedItem into the OnInitialized method.");
return _extendedItem;
}
}
/// <summary>
/// Gets the design context of the extended item. "Context" is equivalent to "ExtendedItem.Context".
/// </summary>
public DesignContext Context {
get {
return this.ExtendedItem.Context;
}
}
/// <summary>
/// Gets the service container of the extended item. "Services" is equivalent to "ExtendedItem.Services".
/// </summary>
public ServiceContainer Services {
get {
return this.ExtendedItem.Services;
}
}
/// <summary>
/// Is called after the ExtendedItem was set.
/// </summary>
protected virtual void OnInitialized()
{
}
sealed class BehaviorExtensionServer : ExtensionServer
{
public override bool ShouldApplyExtensions(DesignItem extendedItem)
{
return true;
}
public override Extension CreateExtension(Type extensionType, DesignItem extendedItem)
{
BehaviorExtension ext = (BehaviorExtension)Activator.CreateInstance(extensionType);
ext._extendedItem = extendedItem;
ext.OnInitialized();
return ext;
}
public override void RemoveExtension(Extension extension)
{
}
}
}
}

7
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs

@ -6,12 +6,19 @@ @@ -6,12 +6,19 @@
// </file>
using System;
using System.Diagnostics;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Base class for all Extensions.
/// </summary>
/// <remarks>
/// The class design in the ICSharpCode.WpfDesign.Extensions namespace was made to match that of Cider
/// as described in the blog posts:
/// http://blogs.msdn.com/jnak/archive/2006/04/24/580393.aspx
/// http://blogs.msdn.com/jnak/archive/2006/08/04/687166.aspx
/// </remarks>
public abstract class Extension
{
}

56
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionForAttribute.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Attribute to specify that the decorated class is a WPF extension for the specified item type.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
public sealed class ExtensionForAttribute : Attribute
{
Type _designedItemType;
Type _overrideExtension;
/// <summary>
/// Gets the type of the item that is designed using this extension.
/// </summary>
public Type DesignedItemType {
get { return _designedItemType; }
}
/// <summary>
/// Gets/Sets the type of another extension that this extension is overriding.
/// </summary>
public Type OverrideExtension {
get { return _overrideExtension; }
set {
_overrideExtension = value;
if (value != null) {
if (!typeof(Extension).IsAssignableFrom(value)) {
throw new ArgumentException("OverrideExtension must specify the type of an Extension.");
}
}
}
}
/// <summary>
/// Create a new ExtensionForAttribute that specifies that the decorated class
/// is a WPF extension for the specified item type.
/// </summary>
public ExtensionForAttribute(Type designedItemType)
{
if (designedItemType == null)
throw new ArgumentNullException("designedItemType");
if (!designedItemType.IsClass)
throw new ArgumentException("designedItemType must be a class");
_designedItemType = designedItemType;
}
}
}

190
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs

@ -0,0 +1,190 @@ @@ -0,0 +1,190 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Reflection;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Manages extension creation for a design context.
/// </summary>
public sealed class ExtensionManager
{
readonly DesignContext _context;
internal ExtensionManager(DesignContext context)
{
Debug.Assert(context != null);
this._context = context;
context.Services.Subscribe<IComponentService>(
delegate(IComponentService componentService) {
componentService.ComponentRegistered += OnComponentRegistered;
});
}
void OnComponentRegistered(object sender, DesignItemEventArgs e)
{
e.Item.SetExtensionServers(GetExtensionServersForItem(e.Item));
e.Item.ApplyExtensions(this);
}
#region Manage ExtensionEntries
sealed class ExtensionEntry
{
internal readonly Type ExtensionType;
internal readonly ExtensionServer Server;
internal readonly Type OverriddenExtensionType;
public ExtensionEntry(Type extensionType, ExtensionServer server, Type overriddenExtensionType)
{
this.ExtensionType = extensionType;
this.Server = server;
this.OverriddenExtensionType = overriddenExtensionType;
}
}
Dictionary<Type, List<ExtensionEntry>> _extensions = new Dictionary<Type, List<ExtensionEntry>>();
void AddExtensionEntry(Type extendedItemType, ExtensionEntry entry)
{
List<ExtensionEntry> list;
if (!_extensions.TryGetValue(extendedItemType, out list)) {
list = _extensions[extendedItemType] = new List<ExtensionEntry>();
}
list.Add(entry);
}
List<ExtensionEntry> GetExtensionEntries(Type extendedItemType)
{
List<ExtensionEntry> result;
if (extendedItemType.BaseType != null)
result = GetExtensionEntries(extendedItemType.BaseType);
else
result = new List<ExtensionEntry>();
List<ExtensionEntry> list;
if (_extensions.TryGetValue(extendedItemType, out list)) {
foreach (ExtensionEntry entry in list) {
if (entry.OverriddenExtensionType != null) {
result.RemoveAll(delegate(ExtensionEntry oldEntry) {
return oldEntry.ExtensionType == entry.OverriddenExtensionType;
});
}
result.Add(entry);
}
}
return result;
}
#endregion
#region Create Extensions
static readonly ExtensionEntry[] emptyExtensionEntryArray = new ExtensionEntry[0];
IEnumerable<ExtensionEntry> GetExtensionEntries(DesignItem extendedItem)
{
if (extendedItem.Component == null)
return emptyExtensionEntryArray;
else
return GetExtensionEntries(extendedItem.Component.GetType());
}
ExtensionServer[] GetExtensionServersForItem(DesignItem item)
{
Debug.Assert(item != null);
HashSet<ExtensionServer> servers = new HashSet<ExtensionServer>();
foreach (ExtensionEntry entry in GetExtensionEntries(item)) {
servers.Add(entry.Server);
}
return Linq.ToArray(servers);
}
internal IEnumerable<Extension> CreateExtensions(ExtensionServer server, DesignItem item)
{
Debug.Assert(server != null);
Debug.Assert(item != null);
foreach (ExtensionEntry entry in GetExtensionEntries(item)) {
if (entry.Server == server) {
yield return server.CreateExtension(entry.ExtensionType, item);
}
}
}
#endregion
#region RegisterAssembly
HashSet<Assembly> _registeredAssemblies = new HashSet<Assembly>();
/// <summary>
/// Registers extensions from the specified assembly.
/// </summary>
public void RegisterAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
// object[] assemblyAttributes = assembly.GetCustomAttributes(typeof(IsWpfDesignerAssemblyAttribute), false);
// if (assemblyAttributes.Length == 0)
// return;
if (!_registeredAssemblies.Add(assembly)) {
// the assembly already is registered, don't try to register it again.
return;
}
// IsWpfDesignerAssemblyAttribute isWpfDesignerAssembly = (IsWpfDesignerAssemblyAttribute)assemblyAttributes[0];
// foreach (Type type in isWpfDesignerAssembly.UsePrivateReflection ? assembly.GetTypes() : assembly.GetExportedTypes()) {
foreach (Type type in assembly.GetTypes()) {
object[] extensionForAttributes = type.GetCustomAttributes(typeof(ExtensionForAttribute), false);
if (extensionForAttributes.Length == 0)
continue;
foreach (ExtensionForAttribute designerFor in extensionForAttributes) {
ExtensionServer server = GetServerForExtension(type);
AddExtensionEntry(designerFor.DesignedItemType, new ExtensionEntry(type, server, designerFor.OverrideExtension));
}
}
}
#endregion
#region Extension Server Creation
// extension server type => extension server instance
Dictionary<Type, ExtensionServer> _extensionServers = new Dictionary<Type, ExtensionServer>();
ExtensionServer GetServerForExtension(Type extensionType)
{
Debug.Assert(extensionType != null);
foreach (ExtensionServerAttribute esa in extensionType.GetCustomAttributes(typeof(ExtensionServerAttribute), true)) {
return GetExtensionServer(esa);
}
throw new DesignerException("Extension types must have a [ExtensionServer] attribute.");
}
/// <summary>
/// Gets the extension server for the specified extension server attribute.
/// </summary>
public ExtensionServer GetExtensionServer(ExtensionServerAttribute attribute)
{
Type extensionServerType = attribute.ExtensionServerType;
ExtensionServer server;
if (_extensionServers.TryGetValue(extensionServerType, out server))
return server;
server = (ExtensionServer)Activator.CreateInstance(extensionServerType);
server.InitializeExtensionServer(_context);
_extensionServers[extensionServerType] = server;
return server;
}
#endregion
}
}

78
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServer.cs

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Diagnostics;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// An ExtensionServer manages a creating and removing extensions of the specific extension type.
/// For a given DesignContext, a ExtensionServer is created only once.
/// The ExtensionServer can handle events raised by services without having to unregister its events
/// handlers because the ExtensionServer runs for the lifetime of the DesignContext.
/// </summary>
public abstract class ExtensionServer
{
DesignContext _context;
/// <summary>
/// Gets the context this extension server was created for.
/// </summary>
public DesignContext Context {
[DebuggerStepThrough]
get {
if (_context == null)
throw new InvalidOperationException("Cannot access ExtensionServer.Context: " +
"The property is not initialized yet. Please move initialization logic " +
"that depends on Context into the OnInitialized method.");
return _context;
}
}
/// <summary>
/// Gets the service container of the current context. "x.Services" is equivalent to "x.Context.Services".
/// </summary>
public ServiceContainer Services {
[DebuggerStepThrough]
get { return this.Context.Services; }
}
internal void InitializeExtensionServer(DesignContext context)
{
Debug.Assert(this._context == null);
Debug.Assert(context != null);
this._context = context;
OnInitialized();
}
/// <summary>
/// Is called after the extension server is initialized and the <see cref="Context"/> property has been set.
/// </summary>
protected virtual void OnInitialized()
{
}
/// <summary>
/// Gets if the extension manager should apply the extensions from this server to the specified item.
/// Is called by the ExtensionManager.
/// </summary>
public abstract bool ShouldApplyExtensions(DesignItem extendedItem);
/// <summary>
/// Create an extension of the specified type.
/// Is called by the ExtensionManager.
/// </summary>
public abstract Extension CreateExtension(Type extensionType, DesignItem extendedItem);
/// <summary>
/// This method is called before an extension is removed from its DesignItem because it should not be applied anymore.
/// Is called by the ExtensionManager.
/// </summary>
public abstract void RemoveExtension(Extension extension);
}
}

42
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServerAttribute.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.WpfDesign.Extensions
{
/// <summary>
/// Attribute to specify that the decorated class is an extension using the specified extension server.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
public sealed class ExtensionServerAttribute : Attribute
{
Type _extensionServerType;
/// <summary>
/// Gets the type of the item that is designed using this extension.
/// </summary>
public Type ExtensionServerType {
get { return _extensionServerType; }
}
/// <summary>
/// Create a new ExtensionServerAttribute that specifies that the decorated extension
/// uses the specified extension server.
/// </summary>
public ExtensionServerAttribute(Type extensionServerType)
{
if (extensionServerType == null)
throw new ArgumentNullException("extensionServerType");
if (!typeof(ExtensionServer).IsAssignableFrom(extensionServerType))
throw new ArgumentException("extensionServerType must derive from ExtensionServer");
if (extensionServerType.GetConstructor(new Type[0]) == null)
throw new ArgumentException("extensionServerType must have a parameter-less constructor");
_extensionServerType = extensionServerType;
}
}
}

16
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/HashSet.cs → src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/HashSet.cs

@ -11,7 +11,7 @@ using System.Text; @@ -11,7 +11,7 @@ using System.Text;
using System.Collections;
using System.Collections.Specialized;
namespace ICSharpCode.WpfDesign.Designer
namespace ICSharpCode.WpfDesign
{
/// <summary>
/// Represents a set of items. The set does not preserve the order of items and does not allow items to
@ -19,12 +19,16 @@ namespace ICSharpCode.WpfDesign.Designer @@ -19,12 +19,16 @@ namespace ICSharpCode.WpfDesign.Designer
/// It supports collection change notifications and is cloned by sharing the underlying
/// data structure and delaying the actual copy until the next change.
/// </summary>
sealed class HashSet<T> : ICollection<T>, ICollection, ICloneable, INotifyCollectionChanged
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public sealed class HashSet<T> : ICollection<T>, ICollection, ICloneable, INotifyCollectionChanged
where T : class
{
Dictionary<T, object> _dict;
bool _copyOnWrite;
/// <summary>
/// This event is raised whenever the collection changes.
/// </summary>
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <summary>
@ -65,7 +69,10 @@ namespace ICSharpCode.WpfDesign.Designer @@ -65,7 +69,10 @@ namespace ICSharpCode.WpfDesign.Designer
return true;
}
}
/// <summary>
/// Adds a list of items to the set. This is equivalent to calling <see cref="Add"/> for each item in <paramref name="items"/>.
/// </summary>
public void AddRange(IEnumerable<T> items)
{
foreach (T item in items) {
@ -147,6 +154,9 @@ namespace ICSharpCode.WpfDesign.Designer @@ -147,6 +154,9 @@ namespace ICSharpCode.WpfDesign.Designer
}
#region IEnumerable Members
/// <summary>
/// Gets an enumerator to enumerate the items in the set.
/// </summary>
public IEnumerator<T> GetEnumerator()
{
return _dict.Keys.GetEnumerator();

23
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Linq.cs

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace ICSharpCode.WpfDesign
{
// Static helpers that should become extension methods in the future
static class Linq
{
public static T[] ToArray<T>(ICollection<T> collection)
{
T[] arr = new T[collection.Count];
collection.CopyTo(arr, 0);
return arr;
}
}
}

56
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs

@ -18,7 +18,8 @@ namespace ICSharpCode.WpfDesign @@ -18,7 +18,8 @@ namespace ICSharpCode.WpfDesign
/// </summary>
public sealed class ServiceContainer : IServiceProvider
{
Dictionary<Type, object> _services = new Dictionary<Type, object>();
readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
readonly Dictionary<Type, Delegate> _waitingSubscribers = new Dictionary<Type, Delegate>();
/// <summary>
/// Adds a new service to the container.
@ -37,6 +38,12 @@ namespace ICSharpCode.WpfDesign @@ -37,6 +38,12 @@ namespace ICSharpCode.WpfDesign
throw new ArgumentNullException("serviceInstance");
_services.Add(serviceInterface, serviceInstance);
Delegate subscriber;
if (_waitingSubscribers.TryGetValue(serviceInterface, out subscriber)) {
_waitingSubscribers.Remove(serviceInterface);
subscriber.DynamicInvoke(serviceInstance);
}
}
/// <summary>
@ -50,7 +57,7 @@ namespace ICSharpCode.WpfDesign @@ -50,7 +57,7 @@ namespace ICSharpCode.WpfDesign
}
/// <summary>
/// Gets the service object of the specified type.
/// Gets the service object of the type T.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public T GetService<T>() where T : class
@ -58,7 +65,28 @@ namespace ICSharpCode.WpfDesign @@ -58,7 +65,28 @@ namespace ICSharpCode.WpfDesign
return (T)GetService(typeof(T));
}
T GetServiceChecked<T>() where T : class
/// <summary>
/// Subscribes to the service of type T.
/// serviceAvailableAction will be called after the service gets available. If the service is already available,
/// the action will be called immediately.
/// </summary>
public void Subscribe<T>(Action<T> serviceAvailableAction) where T : class
{
T service = GetService<T>();
if (service != null) {
serviceAvailableAction(service);
} else {
Type serviceInterface = typeof(T);
Delegate existingSubscriber;
if (_waitingSubscribers.TryGetValue(serviceInterface, out existingSubscriber)) {
_waitingSubscribers[serviceInterface] = Delegate.Combine(existingSubscriber, serviceAvailableAction);
} else {
_waitingSubscribers[serviceInterface] = serviceAvailableAction;
}
}
}
T GetServiceOrThrowException<T>() where T : class
{
T service = (T)GetService(typeof(T));
if (service == null) {
@ -69,31 +97,41 @@ namespace ICSharpCode.WpfDesign @@ -69,31 +97,41 @@ namespace ICSharpCode.WpfDesign
/// <summary>
/// Gets the <see cref="ISelectionService"/>.
/// This service is guaranteed to always exist -> this property will never return null.
/// Throws an exception if the service is not found.
/// </summary>
public ISelectionService Selection {
get {
return GetServiceChecked<ISelectionService>();
return GetServiceOrThrowException<ISelectionService>();
}
}
/// <summary>
/// Gets the <see cref="IToolService"/>.
/// This service is guaranteed to always exist -> this property will never return null.
/// Throws an exception if the service is not found.
/// </summary>
public IToolService Tool {
get {
return GetServiceChecked<IToolService>();
return GetServiceOrThrowException<IToolService>();
}
}
/// <summary>
/// Gets the <see cref="IComponentService"/>.
/// This service is guaranteed to always exist -> this property will never return null.
/// Throws an exception if the service is not found.
/// </summary>
public IComponentService Component {
get {
return GetServiceChecked<IComponentService>();
return GetServiceOrThrowException<IComponentService>();
}
}
/// <summary>
/// Gets the <see cref="ExtensionManager"/>.
/// Throws an exception if the service is not found.
/// </summary>
public Extensions.ExtensionManager ExtensionManager {
get {
return GetServiceOrThrowException<Extensions.ExtensionManager>();
}
}
}

9
src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
<DelaySign>False</DelaySign>
<AssemblyOriginatorKeyMode>File</AssemblyOriginatorKeyMode>
<OutputPath>..\..\..\..\..\..\AddIns\AddIns\DisplayBindings\WpfDesign\</OutputPath>
<RunCodeAnalysis>False</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Globalization#CA1303</CodeAnalysisRules>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
@ -59,7 +61,14 @@ @@ -59,7 +61,14 @@
<Compile Include="EventArgs.cs" />
<Compile Include="Configuration\AssemblyInfo.cs" />
<Compile Include="DesignerException.cs" />
<Compile Include="Extensions\BehaviorExtension.cs" />
<Compile Include="Extensions\Extension.cs" />
<Compile Include="Extensions\ExtensionForAttribute.cs" />
<Compile Include="Extensions\ExtensionManager.cs" />
<Compile Include="Extensions\ExtensionServer.cs" />
<Compile Include="Extensions\ExtensionServerAttribute.cs" />
<Compile Include="HashSet.cs" />
<Compile Include="Linq.cs" />
<Compile Include="ServiceContainer.cs" />
<Compile Include="DesignItem.cs" />
<Compile Include="Services.cs" />

Loading…
Cancel
Save