Browse Source

Support for DesignTimeProperties wich are not defined in Assemblys

like x:DesignHeight, x:IsHidden, etc...
pull/52/head
jkuehner 12 years ago
parent
commit
fcdab5042c
  1. 113
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/DesignTimeProperties.cs
  2. 28
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupCompatibilityProperties.cs
  3. 4
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj
  4. 18
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlConstants.cs
  5. 105
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs
  6. 20
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
  7. 973
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs
  8. 77
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTypeFinder.cs

113
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/DesignTimeProperties.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
using System.Security.Cryptography;
using System.Windows;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Helper Class for the Design Time Properties used by VS and Blend
/// </summary>
public class DesignTimeProperties : FrameworkElement
{
#region IsHidden
public static bool GetIsHidden(DependencyObject obj)
{
return (bool)obj.GetValue(IsHiddenProperty);
}
public static void SetIsHidden(DependencyObject obj, bool value)
{
obj.SetValue(IsHiddenProperty, value);
}
public static readonly DependencyProperty IsHiddenProperty =
DependencyProperty.RegisterAttached("IsHidden", typeof(bool), typeof(DesignTimeProperties));
#endregion
#region IsLocked
public static bool GetIsLocked(DependencyObject obj)
{
return (bool)obj.GetValue(IsLockedProperty);
}
public static void SetIsLocked(DependencyObject obj, bool value)
{
obj.SetValue(IsLockedProperty, value);
}
public static readonly DependencyProperty IsLockedProperty =
DependencyProperty.RegisterAttached("IsLocked", typeof(bool), typeof(DesignTimeProperties));
#endregion
#region DataContext
public static object GetDataContext(DependencyObject obj)
{
return (object)obj.GetValue(DataContextProperty);
}
public static void SetDataContext(DependencyObject obj, bool value)
{
obj.SetValue(DataContextProperty, value);
}
public static readonly DependencyProperty DataContextProperty =
DependencyProperty.RegisterAttached("DataContext", typeof(object), typeof(DesignTimeProperties));
#endregion
#region DesignSource
public static object GetDesignSource(DependencyObject obj)
{
return (object)obj.GetValue(DesignSourceProperty);
}
public static void SetDesignSource(DependencyObject obj, bool value)
{
obj.SetValue(DesignSourceProperty, value);
}
public static readonly DependencyProperty DesignSourceProperty =
DependencyProperty.RegisterAttached("DesignSource", typeof(object), typeof(DesignTimeProperties));
#endregion
#region DesignWidth
public static double GetDesignWidth(DependencyObject obj)
{
return (double)obj.GetValue(DesignWidthProperty);
}
public static void SetDesignWidth(DependencyObject obj, double value)
{
obj.SetValue(DesignWidthProperty, value);
}
public static readonly DependencyProperty DesignWidthProperty =
DependencyProperty.RegisterAttached("DesignWidth", typeof(double), typeof(DesignTimeProperties));
#endregion
#region DesignHeight
public static double GetDesignHeight(DependencyObject obj)
{
return (double)obj.GetValue(DesignHeightProperty);
}
public static void SetDesignHeight(DependencyObject obj, double value)
{
obj.SetValue(DesignHeightProperty, value);
}
public static readonly DependencyProperty DesignHeightProperty =
DependencyProperty.RegisterAttached("DesignHeight", typeof(double), typeof(DesignTimeProperties));
#endregion
}
}

28
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/MarkupCompatibilityProperties.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
using System.Security.Cryptography;
using System.Windows;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Helper Class for the Markup Compatibility Properties used by VS and Blend
/// </summary>
public class MarkupCompatibilityProperties : FrameworkElement
{
#region Ignorable
public static string GetIgnorable(DependencyObject obj)
{
return (string)obj.GetValue(IgnorableProperty);
}
public static void SetIgnorable(DependencyObject obj, string value)
{
obj.SetValue(IgnorableProperty, value);
}
public static readonly DependencyProperty IgnorableProperty =
DependencyProperty.RegisterAttached("Ignorable", typeof(string), typeof(MarkupCompatibilityProperties));
#endregion
}
}

4
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj

@ -69,7 +69,9 @@ @@ -69,7 +69,9 @@
<Compile Include="AssemblyInfo.cs" />
<Compile Include="CollectionElementsCollection.cs" />
<Compile Include="CollectionSupport.cs" />
<Compile Include="DesignTimeProperties.cs" />
<Compile Include="IXamlErrorSink.cs" />
<Compile Include="MarkupCompatibilityProperties.cs" />
<Compile Include="MarkupExtensionParser.cs" />
<Compile Include="MarkupExtensionPrinter.cs" />
<Compile Include="PositionXmlDocument.cs" />
@ -88,4 +90,4 @@ @@ -88,4 +90,4 @@
<Compile Include="XamlTypeFinder.cs" />
<Compile Include="XamlTypeResolverProvider.cs" />
</ItemGroup>
</Project>
</Project>

18
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlConstants.cs

@ -30,6 +30,18 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -30,6 +30,18 @@ namespace ICSharpCode.WpfDesign.XamlDom
/// </summary>
public const string PresentationNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
/// <summary>
/// The namespace used for the DesignTime schema.
/// Value: "http://schemas.microsoft.com/expression/blend/2008"
/// </summary>
public const string DesignTimeNamespace = "http://schemas.microsoft.com/expression/blend/2008";
/// <summary>
/// The namespace used for the MarkupCompatibility schema.
/// Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"
/// </summary>
public const string MarkupCompatibilityNamespace = "http://schemas.openxmlformats.org/markup-compatibility/2006";
#endregion
#region Common property names
@ -40,6 +52,12 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -40,6 +52,12 @@ namespace ICSharpCode.WpfDesign.XamlDom
/// </summary>
public const string ResourcesPropertyName = "Resources";
/// <summary>
/// The name of xmlns.
/// Value: "xmlns"
/// </summary>
public const string Xmlns = "xmlns";
#endregion
}
}

105
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlDocument.cs

@ -17,8 +17,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -17,8 +17,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
XamlObject _rootElement;
IServiceProvider _serviceProvider;
XamlTypeFinder _typeFinder;
XamlTypeFinder _typeFinder;
int namespacePrefixCounter;
internal XmlDocument XmlDocument {
@ -166,13 +166,13 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -166,13 +166,13 @@ namespace ICSharpCode.WpfDesign.XamlDom
bool hasStringConverter = c.CanConvertTo(ctx, typeof(string)) && c.CanConvertFrom(typeof(string));
if (forProperty != null && hasStringConverter) {
return new XamlTextValue(this, c.ConvertToInvariantString(ctx, instance));
}
string ns = GetNamespaceFor(elementType);
string prefix = GetPrefixForNamespace(ns);
XmlElement xml = _xmlDoc.CreateElement(prefix, elementType.Name, ns);
}
string ns = GetNamespaceFor(elementType);
string prefix = GetPrefixForNamespace(ns);
XmlElement xml = _xmlDoc.CreateElement(prefix, elementType.Name, ns);
if (hasStringConverter &&
XamlObject.GetContentPropertyName(elementType) != null)
{
@ -184,45 +184,56 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -184,45 +184,56 @@ namespace ICSharpCode.WpfDesign.XamlDom
internal string GetNamespaceFor(Type type)
{
if (type == typeof (DesignTimeProperties))
return XamlConstants.DesignTimeNamespace;
if (type == typeof (MarkupCompatibilityProperties))
return XamlConstants.MarkupCompatibilityNamespace;
return _typeFinder.GetXmlNamespaceFor(type.Assembly, type.Namespace);
}
internal string GetPrefixForNamespace(string @namespace)
{
if (@namespace == XamlConstants.PresentationNamespace)
{
return null;
}
string prefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(@namespace);
if (String.IsNullOrEmpty(prefix))
{
prefix = _typeFinder.GetPrefixForXmlNamespace(@namespace);
string existingNamespaceForPrefix = null;
if (!String.IsNullOrEmpty(prefix))
{
existingNamespaceForPrefix = _xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix);
}
if (String.IsNullOrEmpty(prefix) ||
!String.IsNullOrEmpty(existingNamespaceForPrefix) &&
existingNamespaceForPrefix != @namespace)
{
do
{
prefix = "Controls" + namespacePrefixCounter++;
} while (!String.IsNullOrEmpty(_xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix)));
}
string xmlnsPrefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(XamlConstants.XmlnsNamespace);
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(xmlnsPrefix));
_xmlDoc.DocumentElement.SetAttribute(xmlnsPrefix + ":" + prefix, @namespace);
}
return prefix;
}
internal string GetPrefixForNamespace(string @namespace)
{
if (@namespace == XamlConstants.PresentationNamespace)
{
return null;
}
string prefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(@namespace);
if (String.IsNullOrEmpty(prefix))
{
prefix = _typeFinder.GetPrefixForXmlNamespace(@namespace);
string existingNamespaceForPrefix = null;
if (!String.IsNullOrEmpty(prefix))
{
existingNamespaceForPrefix = _xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix);
}
if (String.IsNullOrEmpty(prefix) ||
!String.IsNullOrEmpty(existingNamespaceForPrefix) &&
existingNamespaceForPrefix != @namespace)
{
do
{
prefix = "Controls" + namespacePrefixCounter++;
} while (!String.IsNullOrEmpty(_xmlDoc.DocumentElement.GetNamespaceOfPrefix(prefix)));
}
string xmlnsPrefix = _xmlDoc.DocumentElement.GetPrefixOfNamespace(XamlConstants.XmlnsNamespace);
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(xmlnsPrefix));
_xmlDoc.DocumentElement.SetAttribute(xmlnsPrefix + ":" + prefix, @namespace);
if (@namespace == XamlConstants.DesignTimeNamespace)
{
var ignorableProp = new XamlProperty(this._rootElement,new XamlDependencyPropertyInfo(MarkupCompatibilityProperties.IgnorableProperty,true));
ignorableProp.SetAttribute(prefix);
}
}
return prefix;
}
}
}

20
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs

@ -430,6 +430,9 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -430,6 +430,9 @@ namespace ICSharpCode.WpfDesign.XamlDom
static XamlPropertyInfo GetPropertyInfo(object elementInstance, Type elementType, XmlAttribute attribute, XamlTypeFinder typeFinder)
{
var ret = GetXamlSpecialProperty(attribute);
if (ret != null)
return ret;
if (attribute.LocalName.Contains(".")) {
return GetPropertyInfo(typeFinder, elementInstance, elementType, GetAttributeNamespace(attribute), attribute.LocalName);
} else {
@ -437,6 +440,21 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -437,6 +440,21 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
internal static XamlPropertyInfo GetXamlSpecialProperty(XmlAttribute attribute)
{
if (attribute.LocalName == "Ignorable" && attribute.NamespaceURI == XamlConstants.MarkupCompatibilityNamespace) {
return FindAttachedProperty(typeof(MarkupCompatibilityProperties), attribute.LocalName);
} else if (attribute.LocalName == "DesignHeight" && attribute.NamespaceURI == XamlConstants.DesignTimeNamespace) {
return FindAttachedProperty(typeof(DesignTimeProperties), attribute.LocalName);
} else if (attribute.LocalName == "DesignWidth" && attribute.NamespaceURI == XamlConstants.DesignTimeNamespace) {
return FindAttachedProperty(typeof(DesignTimeProperties), attribute.LocalName);
} else if (attribute.LocalName == "IsHidden" && attribute.NamespaceURI == XamlConstants.DesignTimeNamespace) {
return FindAttachedProperty(typeof(DesignTimeProperties), attribute.LocalName);
}
return null;
}
internal static XamlPropertyInfo GetPropertyInfo(XamlTypeFinder typeFinder, object elementInstance, Type elementType, string xmlNamespace, string localName)
{
string typeName, propertyName;
@ -449,7 +467,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -449,7 +467,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
return FindAttachedProperty(propertyType, propertyName);
}
}
static void SplitQualifiedIdentifier(string qualifiedName, out string typeName, out string propertyName)
{
int pos = qualifiedName.IndexOf('.');

973
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlProperty.cs

@ -1,351 +1,351 @@ @@ -1,351 +1,351 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Describes a property on a <see cref="XamlObject"/>.
/// </summary>
[DebuggerDisplay("XamlProperty: {PropertyName}")]
public sealed class XamlProperty
{
XamlObject parentObject;
internal readonly XamlPropertyInfo propertyInfo;
XamlPropertyValue propertyValue;
CollectionElementsCollection collectionElements;
bool isCollection;
bool isResources;
static readonly IList<XamlPropertyValue> emptyCollectionElementsArray = new XamlPropertyValue[0];
// for use by parser only
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo, XamlPropertyValue propertyValue)
: this(parentObject, propertyInfo)
{
PossiblyNameChanged(null, propertyValue);
this.propertyValue = propertyValue;
if (propertyValue != null) {
propertyValue.ParentProperty = this;
}
UpdateValueOnInstance();
}
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo)
{
this.parentObject = parentObject;
this.propertyInfo = propertyInfo;
if (propertyInfo.IsCollection) {
isCollection = true;
collectionElements = new CollectionElementsCollection(this);
if (propertyInfo.Name.Equals(XamlConstants.ResourcesPropertyName, StringComparison.Ordinal) &&
propertyInfo.ReturnType == typeof(ResourceDictionary)) {
isResources = true;
}
}
}
/// <summary>
/// Gets the parent object for which this property was declared.
/// </summary>
public XamlObject ParentObject {
get { return parentObject; }
}
/// <summary>
/// Gets the property name.
/// </summary>
public string PropertyName {
get { return propertyInfo.Name; }
}
/// <summary>
/// Gets the type the property is declared on.
/// </summary>
public Type PropertyTargetType {
get { return propertyInfo.TargetType; }
}
/// <summary>
/// Gets if this property is an attached property.
/// </summary>
public bool IsAttached {
get { return propertyInfo.IsAttached; }
}
/// <summary>
/// Gets if this property is an event.
/// </summary>
public bool IsEvent {
get { return propertyInfo.IsEvent; }
}
/// <summary>
/// Gets the return type of the property.
/// </summary>
public Type ReturnType {
get { return propertyInfo.ReturnType; }
}
/// <summary>
/// Gets the type converter used to convert property values to/from string.
/// </summary>
public TypeConverter TypeConverter {
get { return propertyInfo.TypeConverter; }
}
/// <summary>
/// Gets the category of the property.
/// </summary>
public string Category {
get { return propertyInfo.Category; }
}
/// <summary>
/// Gets the value of the property. Can be null if the property is a collection property.
/// </summary>
public XamlPropertyValue PropertyValue {
get { return propertyValue; }
set { SetPropertyValue(value); }
}
/// <summary>
/// Gets if the property represents the FrameworkElement.Resources property that holds a locally-defined resource dictionary.
/// </summary>
public bool IsResources {
get { return isResources; }
}
/// <summary>
/// Gets if the property is a collection property.
/// </summary>
public bool IsCollection {
get { return isCollection; }
}
/// <summary>
/// Gets the collection elements of the property. Is empty if the property is not a collection.
/// </summary>
public IList<XamlPropertyValue> CollectionElements {
get { return collectionElements ?? emptyCollectionElementsArray; }
}
/// <summary>
/// Gets if the property is set.
/// </summary>
public bool IsSet {
get { return propertyValue != null ||
_propertyElement != null; // collection
}
}
/// <summary>
/// Occurs when the value of the IsSet property has changed.
/// </summary>
public event EventHandler IsSetChanged;
/// <summary>
/// Occurs when the value of the property has changed.
/// </summary>
public event EventHandler ValueChanged;
/// <summary>
/// Occurs when MarkupExtension evaluated PropertyValue dosn't changed but ValueOnInstance does.
/// </summary>
public event EventHandler ValueOnInstanceChanged;
void SetPropertyValue(XamlPropertyValue value)
{
// Binding...
//if (IsCollection) {
// throw new InvalidOperationException("Cannot set the value of collection properties.");
//}
bool wasSet = this.IsSet;
PossiblyNameChanged(propertyValue, value);
//reset expression
var xamlObject = propertyValue as XamlObject;
if (xamlObject != null && xamlObject.IsMarkupExtension)
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
propertyValue = value;
propertyValue.ParentProperty = this;
propertyValue.AddNodeTo(this);
UpdateValueOnInstance();
ParentObject.OnPropertyChanged(this);
if (!wasSet) {
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
internal void UpdateValueOnInstance()
{
if (PropertyValue != null) {
try {
ValueOnInstance = PropertyValue.GetValueFor(propertyInfo);
}
catch {
Debug.WriteLine("UpdateValueOnInstance() failed");
}
}
}
/// <summary>
/// Resets the properties value.
/// </summary>
public void Reset()
{
if (IsSet) {
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
ParentObject.OnPropertyChanged(this);
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
}
void ResetInternal()
{
if (propertyValue != null) {
propertyValue.RemoveNodeFromParent();
propertyValue.ParentProperty = null;
propertyValue = null;
}
if (_propertyElement != null) {
_propertyElement.ParentNode.RemoveChild(_propertyElement);
_propertyElement = null;
}
}
XmlElement _propertyElement;
internal void ParserSetPropertyElement(XmlElement propertyElement)
{
XmlElement oldPropertyElement = _propertyElement;
if (oldPropertyElement == propertyElement) return;
_propertyElement = propertyElement;
if (oldPropertyElement != null && IsCollection) {
Debug.WriteLine("Property element for " + this.PropertyName + " already exists, merging..");
foreach (XamlPropertyValue val in this.collectionElements) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
oldPropertyElement.ParentNode.RemoveChild(oldPropertyElement);
}
}
bool IsFirstChildResources(XamlObject obj)
{
return obj.XmlElement.FirstChild != null &&
obj.XmlElement.FirstChild.Name.EndsWith("." + XamlConstants.ResourcesPropertyName) &&
obj.Properties.Where((prop) => prop.IsResources).FirstOrDefault() != null;
}
XmlElement CreatePropertyElement()
{
string ns = parentObject.OwnerDocument.GetNamespaceFor(parentObject.ElementType);
return parentObject.OwnerDocument.XmlDocument.CreateElement(
parentObject.OwnerDocument.GetPrefixForNamespace(ns),
parentObject.ElementType.Name + "." + this.PropertyName,
ns
);
}
internal void AddChildNodeToProperty(XmlNode newChildNode)
{
if (this.IsCollection) {
// this is the default collection
InsertNodeInCollection(newChildNode, collectionElements.Count);
return;
}
if (_propertyElement == null) {
if (PropertyName == parentObject.ContentPropertyName) {
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(newChildNode, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(newChildNode, parentObject.XmlElement.FirstChild);
return;
}
_propertyElement = CreatePropertyElement();
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(_propertyElement, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(_propertyElement, parentObject.XmlElement.FirstChild);
}
_propertyElement.AppendChild(newChildNode);
}
internal void InsertNodeInCollection(XmlNode newChildNode, int index)
{
Debug.Assert(index >= 0 && index <= collectionElements.Count);
XmlElement collection = _propertyElement;
if (collection == null) {
if (collectionElements.Count == 0 && this.PropertyName != this.ParentObject.ContentPropertyName) {
// we have to create the collection element
_propertyElement = CreatePropertyElement();
if (this.IsResources) {
parentObject.XmlElement.PrependChild(_propertyElement);
} else {
parentObject.XmlElement.AppendChild(_propertyElement);
}
collection = _propertyElement;
} else {
// this is the default collection
collection = parentObject.XmlElement;
}
}
if (collectionElements.Count == 0) {
// collection is empty -> we may insert anywhere
collection.AppendChild(newChildNode);
} else if (index == collectionElements.Count) {
// insert after last element in collection
collection.InsertAfter(newChildNode, collectionElements[collectionElements.Count - 1].GetNodeForCollection());
} else {
// insert before specified index
collection.InsertBefore(newChildNode, collectionElements[index].GetNodeForCollection());
}
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
/// <summary>
/// Describes a property on a <see cref="XamlObject"/>.
/// </summary>
[DebuggerDisplay("XamlProperty: {PropertyName}")]
public sealed class XamlProperty
{
XamlObject parentObject;
internal readonly XamlPropertyInfo propertyInfo;
XamlPropertyValue propertyValue;
CollectionElementsCollection collectionElements;
bool isCollection;
bool isResources;
static readonly IList<XamlPropertyValue> emptyCollectionElementsArray = new XamlPropertyValue[0];
// for use by parser only
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo, XamlPropertyValue propertyValue)
: this(parentObject, propertyInfo)
{
PossiblyNameChanged(null, propertyValue);
this.propertyValue = propertyValue;
if (propertyValue != null) {
propertyValue.ParentProperty = this;
}
UpdateValueOnInstance();
}
internal XamlProperty(XamlObject parentObject, XamlPropertyInfo propertyInfo)
{
this.parentObject = parentObject;
this.propertyInfo = propertyInfo;
if (propertyInfo.IsCollection) {
isCollection = true;
collectionElements = new CollectionElementsCollection(this);
if (propertyInfo.Name.Equals(XamlConstants.ResourcesPropertyName, StringComparison.Ordinal) &&
propertyInfo.ReturnType == typeof(ResourceDictionary)) {
isResources = true;
}
}
}
/// <summary>
/// Gets the parent object for which this property was declared.
/// </summary>
public XamlObject ParentObject {
get { return parentObject; }
}
/// <summary>
/// Gets the property name.
/// </summary>
public string PropertyName {
get { return propertyInfo.Name; }
}
/// <summary>
/// Gets the type the property is declared on.
/// </summary>
public Type PropertyTargetType {
get { return propertyInfo.TargetType; }
}
/// <summary>
/// Gets if this property is an attached property.
/// </summary>
public bool IsAttached {
get { return propertyInfo.IsAttached; }
}
/// <summary>
/// Gets if this property is an event.
/// </summary>
public bool IsEvent {
get { return propertyInfo.IsEvent; }
}
/// <summary>
/// Gets the return type of the property.
/// </summary>
public Type ReturnType {
get { return propertyInfo.ReturnType; }
}
/// <summary>
/// Gets the type converter used to convert property values to/from string.
/// </summary>
public TypeConverter TypeConverter {
get { return propertyInfo.TypeConverter; }
}
/// <summary>
/// Gets the category of the property.
/// </summary>
public string Category {
get { return propertyInfo.Category; }
}
/// <summary>
/// Gets the value of the property. Can be null if the property is a collection property.
/// </summary>
public XamlPropertyValue PropertyValue {
get { return propertyValue; }
set { SetPropertyValue(value); }
}
/// <summary>
/// Gets if the property represents the FrameworkElement.Resources property that holds a locally-defined resource dictionary.
/// </summary>
public bool IsResources {
get { return isResources; }
}
/// <summary>
/// Gets if the property is a collection property.
/// </summary>
public bool IsCollection {
get { return isCollection; }
}
/// <summary>
/// Gets the collection elements of the property. Is empty if the property is not a collection.
/// </summary>
public IList<XamlPropertyValue> CollectionElements {
get { return collectionElements ?? emptyCollectionElementsArray; }
}
/// <summary>
/// Gets if the property is set.
/// </summary>
public bool IsSet {
get { return propertyValue != null ||
_propertyElement != null; // collection
}
}
/// <summary>
/// Occurs when the value of the IsSet property has changed.
/// </summary>
public event EventHandler IsSetChanged;
/// <summary>
/// Occurs when the value of the property has changed.
/// </summary>
public event EventHandler ValueChanged;
/// <summary>
/// Occurs when MarkupExtension evaluated PropertyValue dosn't changed but ValueOnInstance does.
/// </summary>
public event EventHandler ValueOnInstanceChanged;
void SetPropertyValue(XamlPropertyValue value)
{
// Binding...
//if (IsCollection) {
// throw new InvalidOperationException("Cannot set the value of collection properties.");
//}
bool wasSet = this.IsSet;
PossiblyNameChanged(propertyValue, value);
//reset expression
var xamlObject = propertyValue as XamlObject;
if (xamlObject != null && xamlObject.IsMarkupExtension)
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
propertyValue = value;
propertyValue.ParentProperty = this;
propertyValue.AddNodeTo(this);
UpdateValueOnInstance();
ParentObject.OnPropertyChanged(this);
if (!wasSet) {
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
internal void UpdateValueOnInstance()
{
if (PropertyValue != null) {
try {
ValueOnInstance = PropertyValue.GetValueFor(propertyInfo);
}
catch {
Debug.WriteLine("UpdateValueOnInstance() failed");
}
}
}
/// <summary>
/// Resets the properties value.
/// </summary>
public void Reset()
{
if (IsSet) {
propertyInfo.ResetValue(parentObject.Instance);
ResetInternal();
ParentObject.OnPropertyChanged(this);
if (IsSetChanged != null) {
IsSetChanged(this, EventArgs.Empty);
}
if (ValueChanged != null) {
ValueChanged(this, EventArgs.Empty);
}
}
}
void ResetInternal()
{
if (propertyValue != null) {
propertyValue.RemoveNodeFromParent();
propertyValue.ParentProperty = null;
propertyValue = null;
}
if (_propertyElement != null) {
_propertyElement.ParentNode.RemoveChild(_propertyElement);
_propertyElement = null;
}
}
XmlElement _propertyElement;
internal void ParserSetPropertyElement(XmlElement propertyElement)
{
XmlElement oldPropertyElement = _propertyElement;
if (oldPropertyElement == propertyElement) return;
_propertyElement = propertyElement;
if (oldPropertyElement != null && IsCollection) {
Debug.WriteLine("Property element for " + this.PropertyName + " already exists, merging..");
foreach (XamlPropertyValue val in this.collectionElements) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
oldPropertyElement.ParentNode.RemoveChild(oldPropertyElement);
}
}
bool IsFirstChildResources(XamlObject obj)
{
return obj.XmlElement.FirstChild != null &&
obj.XmlElement.FirstChild.Name.EndsWith("." + XamlConstants.ResourcesPropertyName) &&
obj.Properties.Where((prop) => prop.IsResources).FirstOrDefault() != null;
}
XmlElement CreatePropertyElement()
{
string ns = parentObject.OwnerDocument.GetNamespaceFor(parentObject.ElementType);
return parentObject.OwnerDocument.XmlDocument.CreateElement(
parentObject.OwnerDocument.GetPrefixForNamespace(ns),
parentObject.ElementType.Name + "." + this.PropertyName,
ns
);
}
internal void AddChildNodeToProperty(XmlNode newChildNode)
{
if (this.IsCollection) {
// this is the default collection
InsertNodeInCollection(newChildNode, collectionElements.Count);
return;
}
if (_propertyElement == null) {
if (PropertyName == parentObject.ContentPropertyName) {
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(newChildNode, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(newChildNode, parentObject.XmlElement.FirstChild);
return;
}
_propertyElement = CreatePropertyElement();
if (IsFirstChildResources(parentObject)) {
// Resources element should always be first
parentObject.XmlElement.InsertAfter(_propertyElement, parentObject.XmlElement.FirstChild);
}
else
parentObject.XmlElement.InsertBefore(_propertyElement, parentObject.XmlElement.FirstChild);
}
_propertyElement.AppendChild(newChildNode);
}
internal void InsertNodeInCollection(XmlNode newChildNode, int index)
{
Debug.Assert(index >= 0 && index <= collectionElements.Count);
XmlElement collection = _propertyElement;
if (collection == null) {
if (collectionElements.Count == 0 && this.PropertyName != this.ParentObject.ContentPropertyName) {
// we have to create the collection element
_propertyElement = CreatePropertyElement();
if (this.IsResources) {
parentObject.XmlElement.PrependChild(_propertyElement);
} else {
parentObject.XmlElement.AppendChild(_propertyElement);
}
collection = _propertyElement;
} else {
// this is the default collection
collection = parentObject.XmlElement;
}
}
if (collectionElements.Count == 0) {
// collection is empty -> we may insert anywhere
collection.AppendChild(newChildNode);
} else if (index == collectionElements.Count) {
// insert after last element in collection
collection.InsertAfter(newChildNode, collectionElements[collectionElements.Count - 1].GetNodeForCollection());
} else {
// insert before specified index
collection.InsertBefore(newChildNode, collectionElements[index].GetNodeForCollection());
}
}
internal XmlAttribute SetAttribute(string value)
@ -355,17 +355,20 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -355,17 +355,20 @@ namespace ICSharpCode.WpfDesign.XamlDom
if (IsAttached)
{
name = PropertyTargetType.Name + "." + PropertyName;
if (PropertyTargetType == typeof (DesignTimeProperties) || PropertyTargetType == typeof (MarkupCompatibilityProperties))
name = PropertyName;
else
name = PropertyTargetType.Name + "." + PropertyName;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
string prefix = element.GetPrefixOfNamespace(ns);
string prefix = element.GetPrefixOfNamespace(ns);
if (String.IsNullOrEmpty(prefix))
{
prefix = ParentObject.OwnerDocument.GetPrefixForNamespace(ns);
}
if (String.IsNullOrEmpty(prefix))
{
prefix = ParentObject.OwnerDocument.GetPrefixForNamespace(ns);
}
if (!string.IsNullOrEmpty(prefix))
if (!string.IsNullOrEmpty(prefix))
{
element.SetAttribute(name, ns, value);
return element.GetAttributeNode(name, ns);
@ -378,133 +381,133 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -378,133 +381,133 @@ namespace ICSharpCode.WpfDesign.XamlDom
element.SetAttribute(name, value);
return element.GetAttributeNode(name);
}
internal string GetNameForMarkupExtension()
{
if (IsAttached) {
string name = PropertyTargetType.Name + "." + PropertyName;
var element = ParentObject.XmlElement;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
var prefix = element.GetPrefixOfNamespace(ns);
if (string.IsNullOrEmpty(prefix))
return name;
else
return prefix + ":" + name;
}
else
return PropertyName;
}
/// <summary>
/// used internally by the XamlParser.
/// Add a collection element that already is part of the XML DOM.
/// </summary>
internal void ParserAddCollectionElement(XmlElement collectionPropertyElement, XamlPropertyValue val)
{
if (collectionPropertyElement != null && _propertyElement == null) {
ParserSetPropertyElement(collectionPropertyElement);
}
collectionElements.AddInternal(val);
val.ParentProperty = this;
if (collectionPropertyElement != _propertyElement) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
}
/// <summary>
/// Gets/Sets the value of the property on the instance without updating the XAML document.
/// </summary>
public object ValueOnInstance {
get {
if (IsEvent) {
if (propertyValue != null)
return propertyValue.GetValueFor(null);
else
return null;
} else {
return propertyInfo.GetValue(parentObject.Instance);
}
}
set {
propertyInfo.SetValue(parentObject.Instance, value);
if (ValueOnInstanceChanged != null)
ValueOnInstanceChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Gets if this property is considered "advanced" and should be hidden by default in a property grid.
/// </summary>
public bool IsAdvanced {
get { return propertyInfo.IsAdvanced; }
}
/// <summary>
/// Gets the dependency property.
/// </summary>
public DependencyProperty DependencyProperty {
get {
return propertyInfo.DependencyProperty;
}
}
void PossiblyNameChanged(XamlPropertyValue oldValue, XamlPropertyValue newValue)
{
if (PropertyName == "Name" && ReturnType == typeof(string)) {
string oldName = null;
string newName = null;
var oldTextValue = oldValue as XamlTextValue;
if (oldTextValue != null) oldName = oldTextValue.Text;
var newTextValue = newValue as XamlTextValue;
if (newTextValue != null) newName = newTextValue.Text;
var obj = ParentObject;
while (obj != null) {
var nameScope = obj.Instance as INameScope;
if (nameScope == null) {
if (obj.Instance is DependencyObject)
nameScope = NameScope.GetNameScope((DependencyObject)obj.Instance);
}
if (nameScope != null) {
if (oldName != null) {
try {
nameScope.UnregisterName(oldName);
} catch (Exception x) {
Debug.WriteLine(x.Message);
}
}
if (newName != null) {
nameScope.RegisterName(newName, ParentObject.Instance);
}
break;
}
obj = obj.ParentObject;
}
}
}
/*public bool IsAttributeSyntax {
get {
return attribute != null;
}
}
public bool IsElementSyntax {
get {
return element != null;
}
}
public bool IsImplicitDefaultProperty {
get {
return attribute == null && element == null;
}
}*/
}
}
}
internal string GetNameForMarkupExtension()
{
if (IsAttached) {
string name = PropertyTargetType.Name + "." + PropertyName;
var element = ParentObject.XmlElement;
string ns = ParentObject.OwnerDocument.GetNamespaceFor(PropertyTargetType);
var prefix = element.GetPrefixOfNamespace(ns);
if (string.IsNullOrEmpty(prefix))
return name;
else
return prefix + ":" + name;
}
else
return PropertyName;
}
/// <summary>
/// used internally by the XamlParser.
/// Add a collection element that already is part of the XML DOM.
/// </summary>
internal void ParserAddCollectionElement(XmlElement collectionPropertyElement, XamlPropertyValue val)
{
if (collectionPropertyElement != null && _propertyElement == null) {
ParserSetPropertyElement(collectionPropertyElement);
}
collectionElements.AddInternal(val);
val.ParentProperty = this;
if (collectionPropertyElement != _propertyElement) {
val.RemoveNodeFromParent();
val.AddNodeTo(this);
}
}
/// <summary>
/// Gets/Sets the value of the property on the instance without updating the XAML document.
/// </summary>
public object ValueOnInstance {
get {
if (IsEvent) {
if (propertyValue != null)
return propertyValue.GetValueFor(null);
else
return null;
} else {
return propertyInfo.GetValue(parentObject.Instance);
}
}
set {
propertyInfo.SetValue(parentObject.Instance, value);
if (ValueOnInstanceChanged != null)
ValueOnInstanceChanged(this, EventArgs.Empty);
}
}
/// <summary>
/// Gets if this property is considered "advanced" and should be hidden by default in a property grid.
/// </summary>
public bool IsAdvanced {
get { return propertyInfo.IsAdvanced; }
}
/// <summary>
/// Gets the dependency property.
/// </summary>
public DependencyProperty DependencyProperty {
get {
return propertyInfo.DependencyProperty;
}
}
void PossiblyNameChanged(XamlPropertyValue oldValue, XamlPropertyValue newValue)
{
if (PropertyName == "Name" && ReturnType == typeof(string)) {
string oldName = null;
string newName = null;
var oldTextValue = oldValue as XamlTextValue;
if (oldTextValue != null) oldName = oldTextValue.Text;
var newTextValue = newValue as XamlTextValue;
if (newTextValue != null) newName = newTextValue.Text;
var obj = ParentObject;
while (obj != null) {
var nameScope = obj.Instance as INameScope;
if (nameScope == null) {
if (obj.Instance is DependencyObject)
nameScope = NameScope.GetNameScope((DependencyObject)obj.Instance);
}
if (nameScope != null) {
if (oldName != null) {
try {
nameScope.UnregisterName(oldName);
} catch (Exception x) {
Debug.WriteLine(x.Message);
}
}
if (newName != null) {
nameScope.RegisterName(newName, ParentObject.Instance);
}
break;
}
obj = obj.ParentObject;
}
}
}
/*public bool IsAttributeSyntax {
get {
return attribute != null;
}
}
public bool IsElementSyntax {
get {
return element != null;
}
}
public bool IsImplicitDefaultProperty {
get {
return attribute == null && element == null;
}
}*/
}
}

77
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTypeFinder.cs

@ -42,13 +42,13 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -42,13 +42,13 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
sealed class XamlNamespace
{
internal readonly string XmlNamespacePrefix;
{
internal readonly string XmlNamespacePrefix;
internal readonly string XmlNamespace;
internal XamlNamespace(string xmlNamespacePrefix, string xmlNamespace)
{
this.XmlNamespacePrefix = xmlNamespacePrefix;
{
this.XmlNamespacePrefix = xmlNamespacePrefix;
this.XmlNamespace = xmlNamespace;
}
@ -109,25 +109,22 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -109,25 +109,22 @@ namespace ICSharpCode.WpfDesign.XamlDom
} else {
return "clr-namespace:" + mapping.Namespace + ";assembly=" + mapping.Assembly.GetName().Name;
}
}
/// <summary>
/// Gets the prefix to use for the specified XML namespace,
/// or null if no suitable prefix could be found.
/// </summary>
public string GetPrefixForXmlNamespace(string xmlNamespace)
{
XamlNamespace ns;
if (namespaces.TryGetValue(xmlNamespace, out ns))
{
return ns.XmlNamespacePrefix;
}
else
{
return null;
}
}
}
/// <summary>
/// Gets the prefix to use for the specified XML namespace,
/// or null if no suitable prefix could be found.
/// </summary>
public string GetPrefixForXmlNamespace(string xmlNamespace)
{
XamlNamespace ns;
if (namespaces.TryGetValue(xmlNamespace, out ns)) {
return ns.XmlNamespacePrefix;
} else {
return null;
}
}
XamlNamespace ParseNamespace(string xmlNamespace)
{
@ -174,19 +171,19 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -174,19 +171,19 @@ namespace ICSharpCode.WpfDesign.XamlDom
public void RegisterAssembly(Assembly assembly)
{
if (assembly == null)
throw new ArgumentNullException("assembly");
Dictionary<string, string> namespacePrefixes = new Dictionary<string, string>();
foreach (XmlnsPrefixAttribute xmlnsPrefix in assembly.GetCustomAttributes(typeof(XmlnsPrefixAttribute), true)) {
namespacePrefixes.Add(xmlnsPrefix.XmlNamespace, xmlnsPrefix.Prefix);
}
throw new ArgumentNullException("assembly");
Dictionary<string, string> namespacePrefixes = new Dictionary<string, string>();
foreach (XmlnsPrefixAttribute xmlnsPrefix in assembly.GetCustomAttributes(typeof(XmlnsPrefixAttribute), true)) {
namespacePrefixes.Add(xmlnsPrefix.XmlNamespace, xmlnsPrefix.Prefix);
}
foreach (XmlnsDefinitionAttribute xmlnsDef in assembly.GetCustomAttributes(typeof(XmlnsDefinitionAttribute), true)) {
XamlNamespace ns;
if (!namespaces.TryGetValue(xmlnsDef.XmlNamespace, out ns)) {
string prefix;
namespacePrefixes.TryGetValue(xmlnsDef.XmlNamespace, out prefix);
ns = namespaces[xmlnsDef.XmlNamespace] = new XamlNamespace(prefix, xmlnsDef.XmlNamespace);
XamlNamespace ns;
if (!namespaces.TryGetValue(xmlnsDef.XmlNamespace, out ns)) {
string prefix;
namespacePrefixes.TryGetValue(xmlnsDef.XmlNamespace, out prefix);
ns = namespaces[xmlnsDef.XmlNamespace] = new XamlNamespace(prefix, xmlnsDef.XmlNamespace);
}
if (string.IsNullOrEmpty(xmlnsDef.AssemblyName)) {
AddMappingToNamespace(ns, new AssemblyNamespaceMapping(assembly, xmlnsDef.ClrNamespace));
@ -199,6 +196,17 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -199,6 +196,17 @@ namespace ICSharpCode.WpfDesign.XamlDom
}
}
/// <summary>
/// Register the Namspaces not found in any Assembly, but used by VS and Expression Blend
/// </summary>
public void RegisterFixNamespaces()
{
var ns = namespaces[XamlConstants.DesignTimeNamespace] = new XamlNamespace("d", XamlConstants.DesignTimeNamespace);
AddMappingToNamespace(ns, new AssemblyNamespaceMapping(typeof(DesignTimeProperties).Assembly, typeof(DesignTimeProperties).Namespace));
ns = namespaces[XamlConstants.MarkupCompatibilityNamespace] = new XamlNamespace("mc", XamlConstants.MarkupCompatibilityNamespace);
AddMappingToNamespace(ns, new AssemblyNamespaceMapping(typeof(MarkupCompatibilityProperties).Assembly, typeof(MarkupCompatibilityProperties).Namespace));
}
/// <summary>
/// Load the assembly with the specified name.
/// You can override this method to implement custom assembly lookup.
@ -256,6 +264,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -256,6 +264,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
static WpfTypeFinder()
{
Instance = new XamlTypeFinder();
Instance.RegisterFixNamespaces();
Instance.RegisterAssembly(typeof(MarkupExtension).Assembly); // WindowsBase
Instance.RegisterAssembly(typeof(IAddChild).Assembly); // PresentationCore
Instance.RegisterAssembly(typeof(XamlReader).Assembly); // PresentationFramework

Loading…
Cancel
Save