// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team // // Permission is hereby granted, free of charge, to any person obtaining a copy of this // software and associated documentation files (the "Software"), to deal in the Software // without restriction, including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons // to whom the Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Windows.Markup; using System.Windows; using ICSharpCode.WpfDesign.Extensions; using ICSharpCode.WpfDesign.XamlDom; namespace ICSharpCode.WpfDesign.Designer.Xaml { sealed class XamlComponentService : IComponentService { #region IdentityEqualityComparer sealed class IdentityEqualityComparer : IEqualityComparer { internal static readonly IdentityEqualityComparer Instance = new IdentityEqualityComparer(); int IEqualityComparer.GetHashCode(object obj) { return RuntimeHelpers.GetHashCode(obj); } bool IEqualityComparer.Equals(object x, object y) { return x == y; } } #endregion readonly XamlDesignContext _context; public XamlComponentService(XamlDesignContext context) { this._context = context; } public event EventHandler ComponentRegistered; // TODO: this must not be a dictionary because there's no way to unregister components // however, this isn't critical because our design items will stay alive for the lifetime of the // designer anyway if we don't limit the Undo stack. Dictionary _sites = new Dictionary(IdentityEqualityComparer.Instance); public DesignItem GetDesignItem(object component) { if (component == null) throw new ArgumentNullException("component"); XamlDesignItem site; _sites.TryGetValue(component, out site); return site; } public DesignItem RegisterComponentForDesigner(object component, Type basetype = null) { if (component == null) { component = new NullExtension(); } else if (component is Type) { component = new TypeExtension((Type)component); } object baseobject = basetype != null && component.GetType()!=basetype ? CustomInstanceFactory.CreateObjectInstance(basetype, null) : null; XamlObject xamlobj = _context.Document.CreateObject(component, baseobject); XamlDesignItem item = new XamlDesignItem(xamlobj, _context); _sites.Add(component, item); if (ComponentRegistered != null) { ComponentRegistered(this, new DesignItemEventArgs(item)); } return item; } /// /// registers components from an existing XAML tree /// internal XamlDesignItem RegisterXamlComponentRecursive(XamlObject obj) { if (obj == null) return null; foreach (XamlProperty prop in obj.Properties) { RegisterXamlComponentRecursive(prop.PropertyValue as XamlObject); foreach (XamlPropertyValue val in prop.CollectionElements) { RegisterXamlComponentRecursive(val as XamlObject); } } XamlDesignItem site = new XamlDesignItem(obj, _context); _sites.Add(site.Component, site); if (ComponentRegistered != null) { ComponentRegistered(this, new DesignItemEventArgs(site)); } if (_context.RootItem != null && !string.IsNullOrEmpty(site.Name)) { var nameScope = NameScopeHelper.GetNameScopeFromObject(_context.RootItem.Component); if (nameScope != null) { // The object will be a part of the RootItem namescope, remove local namescope if set NameScopeHelper.ClearNameScopeProperty(obj.Instance); string newName = site.Name; if (nameScope.FindName(newName) != null) { int copyIndex = newName.LastIndexOf("_Copy", StringComparison.Ordinal); if (copyIndex < 0) { newName += "_Copy"; } else if (!newName.EndsWith("_Copy", StringComparison.Ordinal)) { string copyEnd = newName.Substring(copyIndex + "_Copy".Length); int copyEndValue; if (Int32.TryParse(copyEnd, out copyEndValue)) newName = newName.Remove(copyIndex + "_Copy".Length); else newName += "_Copy"; } int i = 1; string newNameTemplate = newName; while (nameScope.FindName(newName) != null) { newName = newNameTemplate + i++; } site.Name = newName; } nameScope.RegisterName(newName, obj.Instance); } } return site; } } }