Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2224 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
18 changed files with 653 additions and 21 deletions
@ -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 |
||||
{ |
||||
|
||||
} |
||||
} |
@ -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) |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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
|
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue