diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs
index dd3bf27b2b..d49c6131a6 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Configuration/AssemblyInfo.cs
@@ -7,6 +7,7 @@ using System.Resources;
using System.Globalization;
using System.Windows;
using System.Runtime.InteropServices;
+using ICSharpCode.WpfDesign.Extensions;
#endregion
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs
new file mode 100644
index 0000000000..c8bfc7dbe3
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/TabItemClickableExtension.cs
@@ -0,0 +1,23 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using ICSharpCode.WpfDesign.Extensions;
+
+namespace ICSharpCode.WpfDesign.Designer.Extensions
+{
+ ///
+ /// Makes the TabItem clickable.
+ ///
+ [ExtensionFor(typeof(TabItem))]
+ public sealed class TabItemClickableExtension : BehaviorExtension
+ {
+
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs
index defcfbe596..63a4231a11 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Linq.cs
@@ -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(ICollection collection)
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
index 49bc669d7b..93ad29feb7 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Services/ToolService.cs
@@ -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
protected virtual void OnStopped() {}
}
- sealed class SelectionTask : TaskBase
+ sealed class SelectionGesture : MouseGestureBase
{
protected override void OnStarted(MouseButtonEventArgs e)
{
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
index 454eba962f..840b6ae382 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
@@ -58,7 +58,7 @@
-
+
@@ -72,6 +72,7 @@
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
index acb4843f58..596ceb23cf 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs
@@ -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);
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs
index 7d5a495982..c9a76b8edb 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignContext.cs
@@ -18,6 +18,14 @@ namespace ICSharpCode.WpfDesign
{
readonly ServiceContainer _services = new ServiceContainer();
+ ///
+ /// Creates a new DesignContext instance.
+ ///
+ protected DesignContext()
+ {
+ _services.AddService(typeof(Extensions.ExtensionManager), new Extensions.ExtensionManager(this));
+ }
+
///
/// Gets the .
///
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
index 326f2c5f3d..2c4b74edac 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/DesignItem.cs
@@ -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
/// The DesignItem connects a component with the service system and the designers.
/// Equivalent to Cider's ModelItem.
///
- ///
- /// 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
- ///
public abstract class DesignItem
{
///
@@ -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 _extensions = new List();
+
+ ///
+ /// Gets the extensions registered for this DesignItem.
+ ///
+ public IEnumerable 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
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs
new file mode 100644
index 0000000000..c447c36d6a
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/BehaviorExtension.cs
@@ -0,0 +1,79 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.WpfDesign.Extensions
+{
+ ///
+ /// 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.
+ ///
+ [ExtensionServer(typeof(BehaviorExtension.BehaviorExtensionServer))]
+ public abstract class BehaviorExtension : Extension
+ {
+ DesignItem _extendedItem;
+
+ ///
+ /// Gets the item that is being extended by the BehaviorExtension.
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Gets the design context of the extended item. "Context" is equivalent to "ExtendedItem.Context".
+ ///
+ public DesignContext Context {
+ get {
+ return this.ExtendedItem.Context;
+ }
+ }
+
+ ///
+ /// Gets the service container of the extended item. "Services" is equivalent to "ExtendedItem.Services".
+ ///
+ public ServiceContainer Services {
+ get {
+ return this.ExtendedItem.Services;
+ }
+ }
+
+ ///
+ /// Is called after the ExtendedItem was set.
+ ///
+ 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)
+ {
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs
index 45ab7340c1..75fc9ad030 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/Extension.cs
@@ -6,12 +6,19 @@
//
using System;
+using System.Diagnostics;
namespace ICSharpCode.WpfDesign.Extensions
{
///
/// Base class for all Extensions.
///
+ ///
+ /// 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
+ ///
public abstract class Extension
{
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionForAttribute.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionForAttribute.cs
new file mode 100644
index 0000000000..01a0ad813e
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionForAttribute.cs
@@ -0,0 +1,56 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.WpfDesign.Extensions
+{
+ ///
+ /// Attribute to specify that the decorated class is a WPF extension for the specified item type.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=true, Inherited=false)]
+ public sealed class ExtensionForAttribute : Attribute
+ {
+ Type _designedItemType;
+ Type _overrideExtension;
+
+ ///
+ /// Gets the type of the item that is designed using this extension.
+ ///
+ public Type DesignedItemType {
+ get { return _designedItemType; }
+ }
+
+ ///
+ /// Gets/Sets the type of another extension that this extension is overriding.
+ ///
+ 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.");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Create a new ExtensionForAttribute that specifies that the decorated class
+ /// is a WPF extension for the specified item type.
+ ///
+ public ExtensionForAttribute(Type designedItemType)
+ {
+ if (designedItemType == null)
+ throw new ArgumentNullException("designedItemType");
+ if (!designedItemType.IsClass)
+ throw new ArgumentException("designedItemType must be a class");
+ _designedItemType = designedItemType;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs
new file mode 100644
index 0000000000..877aec2c2d
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionManager.cs
@@ -0,0 +1,190 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace ICSharpCode.WpfDesign.Extensions
+{
+ ///
+ /// Manages extension creation for a design context.
+ ///
+ public sealed class ExtensionManager
+ {
+ readonly DesignContext _context;
+
+ internal ExtensionManager(DesignContext context)
+ {
+ Debug.Assert(context != null);
+ this._context = context;
+
+ context.Services.Subscribe(
+ 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> _extensions = new Dictionary>();
+
+ void AddExtensionEntry(Type extendedItemType, ExtensionEntry entry)
+ {
+ List list;
+ if (!_extensions.TryGetValue(extendedItemType, out list)) {
+ list = _extensions[extendedItemType] = new List();
+ }
+ list.Add(entry);
+ }
+
+ List GetExtensionEntries(Type extendedItemType)
+ {
+ List result;
+ if (extendedItemType.BaseType != null)
+ result = GetExtensionEntries(extendedItemType.BaseType);
+ else
+ result = new List();
+
+ List 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 GetExtensionEntries(DesignItem extendedItem)
+ {
+ if (extendedItem.Component == null)
+ return emptyExtensionEntryArray;
+ else
+ return GetExtensionEntries(extendedItem.Component.GetType());
+ }
+
+ ExtensionServer[] GetExtensionServersForItem(DesignItem item)
+ {
+ Debug.Assert(item != null);
+
+ HashSet servers = new HashSet();
+ foreach (ExtensionEntry entry in GetExtensionEntries(item)) {
+ servers.Add(entry.Server);
+ }
+ return Linq.ToArray(servers);
+ }
+
+ internal IEnumerable 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 _registeredAssemblies = new HashSet();
+
+ ///
+ /// Registers extensions from the specified assembly.
+ ///
+ 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 _extensionServers = new Dictionary();
+
+ 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.");
+ }
+
+ ///
+ /// Gets the extension server for the specified extension server attribute.
+ ///
+ 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
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServer.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServer.cs
new file mode 100644
index 0000000000..220644f910
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServer.cs
@@ -0,0 +1,78 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Diagnostics;
+
+namespace ICSharpCode.WpfDesign.Extensions
+{
+ ///
+ /// 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.
+ ///
+ public abstract class ExtensionServer
+ {
+ DesignContext _context;
+
+ ///
+ /// Gets the context this extension server was created for.
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// Gets the service container of the current context. "x.Services" is equivalent to "x.Context.Services".
+ ///
+ 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();
+ }
+
+ ///
+ /// Is called after the extension server is initialized and the property has been set.
+ ///
+ protected virtual void OnInitialized()
+ {
+ }
+
+ ///
+ /// Gets if the extension manager should apply the extensions from this server to the specified item.
+ /// Is called by the ExtensionManager.
+ ///
+ public abstract bool ShouldApplyExtensions(DesignItem extendedItem);
+
+ ///
+ /// Create an extension of the specified type.
+ /// Is called by the ExtensionManager.
+ ///
+ public abstract Extension CreateExtension(Type extensionType, DesignItem extendedItem);
+
+ ///
+ /// This method is called before an extension is removed from its DesignItem because it should not be applied anymore.
+ /// Is called by the ExtensionManager.
+ ///
+ public abstract void RemoveExtension(Extension extension);
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServerAttribute.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServerAttribute.cs
new file mode 100644
index 0000000000..7734f9c6de
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/ExtensionServerAttribute.cs
@@ -0,0 +1,42 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+
+namespace ICSharpCode.WpfDesign.Extensions
+{
+ ///
+ /// Attribute to specify that the decorated class is an extension using the specified extension server.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
+ public sealed class ExtensionServerAttribute : Attribute
+ {
+ Type _extensionServerType;
+
+ ///
+ /// Gets the type of the item that is designed using this extension.
+ ///
+ public Type ExtensionServerType {
+ get { return _extensionServerType; }
+ }
+
+ ///
+ /// Create a new ExtensionServerAttribute that specifies that the decorated extension
+ /// uses the specified extension server.
+ ///
+ 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;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/HashSet.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/HashSet.cs
similarity index 87%
rename from src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/HashSet.cs
rename to src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/HashSet.cs
index cafcd32627..a963c79abe 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/HashSet.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/HashSet.cs
@@ -11,7 +11,7 @@ using System.Text;
using System.Collections;
using System.Collections.Specialized;
-namespace ICSharpCode.WpfDesign.Designer
+namespace ICSharpCode.WpfDesign
{
///
/// 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
/// It supports collection change notifications and is cloned by sharing the underlying
/// data structure and delaying the actual copy until the next change.
///
- sealed class HashSet : ICollection, ICollection, ICloneable, INotifyCollectionChanged
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
+ public sealed class HashSet : ICollection, ICollection, ICloneable, INotifyCollectionChanged
where T : class
{
Dictionary _dict;
bool _copyOnWrite;
+ ///
+ /// This event is raised whenever the collection changes.
+ ///
public event NotifyCollectionChangedEventHandler CollectionChanged;
///
@@ -65,7 +69,10 @@ namespace ICSharpCode.WpfDesign.Designer
return true;
}
}
-
+
+ ///
+ /// Adds a list of items to the set. This is equivalent to calling for each item in .
+ ///
public void AddRange(IEnumerable items)
{
foreach (T item in items) {
@@ -147,6 +154,9 @@ namespace ICSharpCode.WpfDesign.Designer
}
#region IEnumerable Members
+ ///
+ /// Gets an enumerator to enumerate the items in the set.
+ ///
public IEnumerator GetEnumerator()
{
return _dict.Keys.GetEnumerator();
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Linq.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Linq.cs
new file mode 100644
index 0000000000..69a7cfdcd5
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Linq.cs
@@ -0,0 +1,23 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+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(ICollection collection)
+ {
+ T[] arr = new T[collection.Count];
+ collection.CopyTo(arr, 0);
+ return arr;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs
index 49288c4cd9..082b3bf4f5 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/ServiceContainer.cs
@@ -18,7 +18,8 @@ namespace ICSharpCode.WpfDesign
///
public sealed class ServiceContainer : IServiceProvider
{
- Dictionary _services = new Dictionary();
+ readonly Dictionary _services = new Dictionary();
+ readonly Dictionary _waitingSubscribers = new Dictionary();
///
/// Adds a new service to the container.
@@ -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);
+ }
}
///
@@ -50,7 +57,7 @@ namespace ICSharpCode.WpfDesign
}
///
- /// Gets the service object of the specified type.
+ /// Gets the service object of the type T.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public T GetService() where T : class
@@ -58,7 +65,28 @@ namespace ICSharpCode.WpfDesign
return (T)GetService(typeof(T));
}
- T GetServiceChecked() where T : class
+ ///
+ /// 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.
+ ///
+ public void Subscribe(Action serviceAvailableAction) where T : class
+ {
+ T service = GetService();
+ 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() where T : class
{
T service = (T)GetService(typeof(T));
if (service == null) {
@@ -69,31 +97,41 @@ namespace ICSharpCode.WpfDesign
///
/// Gets the .
- /// This service is guaranteed to always exist -> this property will never return null.
+ /// Throws an exception if the service is not found.
///
public ISelectionService Selection {
get {
- return GetServiceChecked();
+ return GetServiceOrThrowException();
}
}
///
/// Gets the .
- /// This service is guaranteed to always exist -> this property will never return null.
+ /// Throws an exception if the service is not found.
///
public IToolService Tool {
get {
- return GetServiceChecked();
+ return GetServiceOrThrowException();
}
}
///
/// Gets the .
- /// This service is guaranteed to always exist -> this property will never return null.
+ /// Throws an exception if the service is not found.
///
public IComponentService Component {
get {
- return GetServiceChecked();
+ return GetServiceOrThrowException();
+ }
+ }
+
+ ///
+ /// Gets the .
+ /// Throws an exception if the service is not found.
+ ///
+ public Extensions.ExtensionManager ExtensionManager {
+ get {
+ return GetServiceOrThrowException();
}
}
}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
index 8bacd284b6..478d9a8cf3 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/WpfDesign.csproj
@@ -16,6 +16,8 @@
False
File
..\..\..\..\..\..\AddIns\AddIns\DisplayBindings\WpfDesign\
+ False
+ -Microsoft.Globalization#CA1303
true
@@ -59,7 +61,14 @@
+
+
+
+
+
+
+