Browse Source

Support loading .xaml files that use CDATA-sections.

Support loading .xaml files that set up event handlers.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2423 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 19 years ago
parent
commit
5516b08461
  1. 39
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/Designer/ModelTests.cs
  2. 10
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/TestHelper.cs
  3. 31
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/WhitespaceTests.cs
  4. 69
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs
  5. 1
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/WpfDesign.XamlDom.csproj
  6. 72
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlParser.cs
  7. 96
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs
  8. 17
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs

39
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/Designer/ModelTests.cs

@ -111,6 +111,34 @@ namespace ICSharpCode.WpfDesign.Tests.Designer @@ -111,6 +111,34 @@ namespace ICSharpCode.WpfDesign.Tests.Designer
AssertLog("");
}
[Test]
public void AddTextBoxToCanvasEmptyExplicitPanelChildrenCollection()
{
DesignItem canvas = CreateCanvasContext("<Canvas><Panel.Children></Panel.Children></Canvas>");
DesignItem textBox = canvas.Services.Component.RegisterComponentForDesigner(new TextBox());
canvas.Properties["Children"].CollectionElements.Add(textBox);
AssertCanvasDesignerOutput("<Canvas>\n" +
" <Panel.Children>\n" +
" <TextBox />\n" +
" </Panel.Children>\n" +
"</Canvas>", canvas.Context);
AssertLog("");
}
[Test]
public void AddTextBoxToCanvasEmptyExplicitCanvasChildrenCollection()
{
DesignItem canvas = CreateCanvasContext("<Canvas><Canvas.Children></Canvas.Children></Canvas>");
DesignItem textBox = canvas.Services.Component.RegisterComponentForDesigner(new TextBox());
canvas.Properties["Children"].CollectionElements.Add(textBox);
AssertCanvasDesignerOutput("<Canvas>\n" +
" <Canvas.Children>\n" +
" <TextBox />\n" +
" </Canvas.Children>\n" +
"</Canvas>", canvas.Context);
AssertLog("");
}
[Test]
public void InsertTextBoxInCanvas()
{
@ -129,5 +157,16 @@ namespace ICSharpCode.WpfDesign.Tests.Designer @@ -129,5 +157,16 @@ namespace ICSharpCode.WpfDesign.Tests.Designer
"<Canvas.Height>60</Canvas.Height>", button.Context);
AssertLog("");
}
[Test]
public void ClearImplicitChildCollection()
{
DesignItem canvas = CreateCanvasContext("<Canvas><Button/><TextBox/></Canvas>");
DesignItem textBox = canvas.Services.Component.RegisterComponentForDesigner(new TextBox());
canvas.Properties["Children"].CollectionElements.Clear();
AssertCanvasDesignerOutput("<Canvas>\n" +
"</Canvas>", canvas.Context);
AssertLog("");
}
}
}

10
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/TestHelper.cs

@ -48,8 +48,18 @@ namespace ICSharpCode.WpfDesign.Tests.XamlDom @@ -48,8 +48,18 @@ namespace ICSharpCode.WpfDesign.Tests.XamlDom
string officialSaved = XamlWriter.Save(officialResult);
string ownSaved = XamlWriter.Save(ownResult);
Debug.WriteLine("Official saved:");
Debug.WriteLine(officialSaved);
Debug.WriteLine("Own saved:");
Debug.WriteLine(ownSaved);
Assert.AreEqual(officialSaved, ownSaved);
Debug.WriteLine("Official log:");
Debug.WriteLine(officialLog);
Debug.WriteLine("Own log:");
Debug.WriteLine(ownLog);
// compare logs:
Assert.AreEqual(officialLog, ownLog);
}

31
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/XamlDom/WhitespaceTests.cs

@ -96,5 +96,36 @@ namespace ICSharpCode.WpfDesign.Tests.XamlDom @@ -96,5 +96,36 @@ namespace ICSharpCode.WpfDesign.Tests.XamlDom
</t:ExampleClass>
");
}
[Test]
public void CDataTest()
{
TestLoading(@"
<t:ExampleClass
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:t=""" + XamlTypeFinderTests.XamlDomTestsNamespace + @"""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" xml:space=""preserve""> <![CDATA[
This is text inside the CData section.
This is another line of text.
This one is indented again.
And that was an empty line.
]]>
</t:ExampleClass>");
}
[Test]
public void CDataAndContentMixTest()
{
TestLoading(@"
<t:ExampleClass
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:t=""" + XamlTypeFinderTests.XamlDomTestsNamespace + @"""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
some text
<![CDATA[ text in <CDATA> ]]>
more text
</t:ExampleClass>");
}
}
}

69
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/CollectionSupport.cs

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
// <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;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
namespace ICSharpCode.WpfDesign.XamlDom
{
static class CollectionSupport
{
public static bool IsCollectionType(Type type)
{
return typeof(IList).IsAssignableFrom(type)
|| typeof(IDictionary).IsAssignableFrom(type)
|| type.IsArray
|| typeof(IAddChild).IsAssignableFrom(type);
}
public static void AddToCollection(Type collectionType, object collectionInstance, XamlPropertyValue newElement)
{
IAddChild addChild = collectionInstance as IAddChild;
if (addChild != null) {
if (newElement is XamlTextValue) {
addChild.AddText((string)newElement.GetValueFor(null));
} else {
addChild.AddChild(newElement.GetValueFor(null));
}
} else {
collectionType.InvokeMember(
"Add", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
null, collectionInstance,
new object[] { newElement.GetValueFor(null) },
CultureInfo.InvariantCulture);
}
}
static readonly Type[] RemoveAtParameters = { typeof(int) };
public static bool RemoveItemAt(Type collectionType, object collectionInstance, int index)
{
MethodInfo m = collectionType.GetMethod("RemoveAt", RemoveAtParameters);
if (m != null) {
m.Invoke(collectionInstance, new object[] { index });
return true;
} else {
return false;
}
}
public static void RemoveItem(Type collectionType, object collectionInstance, object item)
{
collectionType.InvokeMember(
"Remove", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
null, collectionInstance,
new object[] { item },
CultureInfo.InvariantCulture);
}
}
}

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

@ -59,6 +59,7 @@ @@ -59,6 +59,7 @@
</Compile>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="CollectionElementsCollection.cs" />
<Compile Include="CollectionSupport.cs" />
<Compile Include="XamlConstants.cs" />
<Compile Include="XamlDocument.cs" />
<Compile Include="XamlLoadException.cs" />

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

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@ -189,7 +190,16 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -189,7 +190,16 @@ namespace ICSharpCode.WpfDesign.XamlDom
obj.AddProperty(defaultCollectionProperty = new XamlProperty(obj, defaultProperty, null));
}
foreach (XmlNode childNode in element.ChildNodes) {
foreach (XmlNode childNode in GetNormalizedChildNodes(element)) {
// I don't know why the official XamlReader runs the property getter
// here, but let's try to imitate it as good as possible
if (defaultProperty != null && !defaultProperty.IsCollection) {
for (; combinedNormalizedChildNodes > 0; combinedNormalizedChildNodes--) {
defaultProperty.GetValue(instance);
}
}
XmlElement childElement = childNode as XmlElement;
if (childElement != null) {
if (ObjectChildElementIsPropertyElement(childElement)) {
@ -240,12 +250,53 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -240,12 +250,53 @@ namespace ICSharpCode.WpfDesign.XamlDom
return obj;
}
int combinedNormalizedChildNodes;
IEnumerable<XmlNode> GetNormalizedChildNodes(XmlElement element)
{
XmlNode node = element.FirstChild;
while (node != null) {
XmlText text = node as XmlText;
XmlCDataSection cData = node as XmlCDataSection;
if (node.NodeType == XmlNodeType.SignificantWhitespace) {
text = element.OwnerDocument.CreateTextNode(node.Value);
element.ReplaceChild(text, node);
node = text;
}
if (text != null || cData != null) {
node = node.NextSibling;
while (node != null
&& (node.NodeType == XmlNodeType.Text
|| node.NodeType == XmlNodeType.CDATA
|| node.NodeType == XmlNodeType.SignificantWhitespace))
{
combinedNormalizedChildNodes++;
if (text != null) text.Value += node.Value;
else cData.Value += node.Value;
XmlNode nodeToDelete = node;
node = node.NextSibling;
element.RemoveChild(nodeToDelete);
}
if (text != null) yield return text;
else yield return cData;
} else {
yield return node;
node = node.NextSibling;
}
}
}
XamlPropertyValue ParseValue(XmlNode childNode)
{
XmlText childText = childNode as XmlText;
if (childText != null) {
return new XamlTextValue(childText, currentXmlSpace);
}
XmlCDataSection cData = childNode as XmlCDataSection;
if (cData != null) {
return new XamlTextValue(cData, currentXmlSpace);
}
XmlElement element = childNode as XmlElement;
if (element != null) {
return ParseObject(element);
@ -270,15 +321,25 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -270,15 +321,25 @@ namespace ICSharpCode.WpfDesign.XamlDom
properties = TypeDescriptor.GetProperties(propertyType);
}
PropertyDescriptor propertyInfo = properties[propertyName];
if (propertyInfo == null) {
if (propertyInfo != null) {
return new XamlNormalPropertyInfo(propertyInfo);
} else {
XamlPropertyInfo pi = TryFindAttachedProperty(propertyType, propertyName);
if (pi != null) {
return pi;
} else {
throw new XamlLoadException("property " + propertyName + " not found");
}
}
return new XamlNormalPropertyInfo(propertyInfo);
EventDescriptorCollection events;
if (elementInstance != null) {
events = TypeDescriptor.GetEvents(elementInstance);
} else {
events = TypeDescriptor.GetEvents(propertyType);
}
EventDescriptor eventInfo = events[propertyName];
if (eventInfo != null) {
return new XamlEventPropertyInfo(eventInfo);
}
throw new XamlLoadException("property " + propertyName + " not found");
}
internal static XamlPropertyInfo TryFindAttachedProperty(Type elementType, string propertyName)
@ -372,6 +433,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -372,6 +433,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
if (collectionProperty == null) {
obj.AddProperty(collectionProperty = new XamlProperty(obj, propertyInfo, null));
}
collectionProperty.ParserSetPropertyElement(element);
}
XmlSpace oldXmlSpace = currentXmlSpace;

96
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlPropertyInfo.cs

@ -32,10 +32,12 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -32,10 +32,12 @@ namespace ICSharpCode.WpfDesign.XamlDom
public abstract string FullyQualifiedName { get; }
public abstract bool IsAttached { get; }
public abstract bool IsCollection { get; }
public virtual bool IsEvent { get { return false; } }
public abstract string Category { get; }
internal abstract void AddValue(object collectionInstance, XamlPropertyValue newElement);
}
#region XamlDependencyPropertyInfo
internal class XamlDependencyPropertyInfo : XamlPropertyInfo
{
readonly DependencyProperty property;
@ -104,7 +106,9 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -104,7 +106,9 @@ namespace ICSharpCode.WpfDesign.XamlDom
throw new NotSupportedException();
}
}
#endregion
#region XamlNormalPropertyInfo
internal sealed class XamlNormalPropertyInfo : XamlPropertyInfo
{
PropertyDescriptor _propertyDescriptor;
@ -175,55 +179,75 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -175,55 +179,75 @@ namespace ICSharpCode.WpfDesign.XamlDom
CollectionSupport.AddToCollection(_propertyDescriptor.PropertyType, collectionInstance, newElement);
}
}
#endregion
static class CollectionSupport
#region XamlEventPropertyInfo
sealed class XamlEventPropertyInfo : XamlPropertyInfo
{
public static bool IsCollectionType(Type type)
readonly EventDescriptor _eventDescriptor;
public XamlEventPropertyInfo(EventDescriptor eventDescriptor)
{
return typeof(IList).IsAssignableFrom(type)
|| typeof(IDictionary).IsAssignableFrom(type)
|| type.IsArray
|| typeof(IAddChild).IsAssignableFrom(type);
this._eventDescriptor = eventDescriptor;
}
public static void AddToCollection(Type collectionType, object collectionInstance, XamlPropertyValue newElement)
public override object GetValue(object instance)
{
IAddChild addChild = collectionInstance as IAddChild;
if (addChild != null) {
if (newElement is XamlTextValue) {
addChild.AddText((string)newElement.GetValueFor(null));
} else {
addChild.AddChild(newElement.GetValueFor(null));
}
} else {
collectionType.InvokeMember(
"Add", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
null, collectionInstance,
new object[] { newElement.GetValueFor(null) },
CultureInfo.InvariantCulture);
}
return null;
}
static readonly Type[] RemoveAtParameters = { typeof(int) };
public override void SetValue(object instance, object value)
{
}
public static bool RemoveItemAt(Type collectionType, object collectionInstance, int index)
public override void ResetValue(object instance)
{
MethodInfo m = collectionType.GetMethod("RemoveAt", RemoveAtParameters);
if (m != null) {
m.Invoke(collectionInstance, new object[] { index });
return true;
} else {
return false;
}
public override Type ReturnType {
get { return _eventDescriptor.EventType; }
}
public override Type TargetType {
get { return _eventDescriptor.ComponentType; }
}
public override string Category {
get { return _eventDescriptor.Category; }
}
public override TypeConverter TypeConverter {
get { return null; }
}
public override string FullyQualifiedName {
get {
return _eventDescriptor.ComponentType.FullName + "." + _eventDescriptor.Name;
}
}
public static void RemoveItem(Type collectionType, object collectionInstance, object item)
public override string Name {
get { return _eventDescriptor.Name; }
}
public override bool IsEvent {
get { return true; }
}
public override bool IsAttached {
get { return false; }
}
public override bool IsCollection {
get { return false; }
}
internal override void AddValue(object collectionInstance, XamlPropertyValue newElement)
{
collectionType.InvokeMember(
"Remove", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance,
null, collectionInstance,
new object[] { item },
CultureInfo.InvariantCulture);
throw new NotSupportedException();
}
}
#endregion
}

17
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.XamlDom/Project/XamlTextValue.cs

@ -23,6 +23,7 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -23,6 +23,7 @@ namespace ICSharpCode.WpfDesign.XamlDom
XmlText textNode;
XmlSpace xmlSpace;
string textValue;
XmlCDataSection cDataSection;
internal XamlTextValue(XmlAttribute attribute)
{
@ -40,6 +41,12 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -40,6 +41,12 @@ namespace ICSharpCode.WpfDesign.XamlDom
this.textNode = textNode;
}
internal XamlTextValue(XmlCDataSection cDataSection, XmlSpace xmlSpace)
{
this.xmlSpace = xmlSpace;
this.cDataSection = cDataSection;
}
/// <summary>
/// The text represented by the value.
/// </summary>
@ -49,6 +56,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -49,6 +56,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
return attribute.Value;
else if (textValue != null)
return textValue;
else if (cDataSection != null)
return cDataSection.Value;
else
return NormalizeWhitespace(textNode.Value);
}
@ -60,6 +69,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -60,6 +69,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
attribute.Value = value;
else if (textValue != null)
textValue = value;
else if (cDataSection != null)
cDataSection.Value = value;
else
textNode.Value = value;
}
@ -106,6 +117,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -106,6 +117,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
attribute.OwnerElement.RemoveAttribute(attribute.Name);
else if (textNode != null)
textNode.ParentNode.RemoveChild(textNode);
else if (cDataSection != null)
cDataSection.ParentNode.RemoveChild(cDataSection);
}
internal override void AddNodeTo(XamlProperty property)
@ -127,6 +140,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -127,6 +140,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
attribute = property.ParentObject.XmlElement.GetAttributeNode(name, ns);
}
textValue = null;
} else if (cDataSection != null) {
property.AddChildNodeToProperty(cDataSection);
} else {
property.AddChildNodeToProperty(textNode);
}
@ -136,6 +151,8 @@ namespace ICSharpCode.WpfDesign.XamlDom @@ -136,6 +151,8 @@ namespace ICSharpCode.WpfDesign.XamlDom
{
if (textNode != null)
return textNode;
else if (cDataSection != null)
return cDataSection;
else
throw new NotImplementedException();
}

Loading…
Cancel
Save