Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

using ICSharpCode.WpfDesign.Designer.Xaml;
using ICSharpCode.WpfDesign.XamlDom;
Expand All @@ -14,6 +16,15 @@ namespace ICSharpCode.WpfDesign.Tests.Designer
[TestFixture]
public class EditOperationTests : ModelTestHelper
{
protected override XamlLoadSettings CreateXamlLoadSettings()
{
var settings = base.CreateXamlLoadSettings();

settings.TypeFinder.RegisterAssembly(typeof(NamespaceTests).Assembly);

return settings;
}

Mutex mutex;

[TestFixtureSetUp]
Expand Down Expand Up @@ -204,5 +215,108 @@ public void PasteSameElementMultipleTimesCheckCopiesNames()
Assert.IsNotNull(nameScope.FindName(_name + "_Copy3"));
Assert.IsNull(nameScope.FindName(_name + "_Copy4"));
}

[Test]
public void PasteCustomControlUsingMixedTypes()
{
DesignItem grid = CreateGridContextWithDesignSurface("<Button/>");
DesignItem myButton = grid.Services.Component.RegisterComponentForDesigner(new ICSharpCode.WpfDesign.Tests.Controls.CustomButton());
grid.Properties["Children"].CollectionElements.Add(myButton);

DesignItem extensionItem = grid.Services.Component.RegisterComponentForDesigner(new MyExtension());
extensionItem.Properties["MyProperty1"].SetValue(new Button());
myButton.Properties[ICSharpCode.WpfDesign.Tests.Controls.CustomButton.TagProperty].SetValue(extensionItem);

var xamlContext = grid.Context as XamlDesignContext;
Assert.IsNotNull(xamlContext);
xamlContext.XamlEditAction.Copy(new[] {myButton});

grid = CreateGridContextWithDesignSurface("<Button/>");
xamlContext = grid.Context as XamlDesignContext;
Assert.IsNotNull(xamlContext);
var selection = grid.Services.Selection;
selection.SetSelectedComponents(new[] {grid});
xamlContext.XamlEditAction.Paste();

string expectedXaml = "<Button />\n" +
"<sdtcontrols:CustomButton>\n" +
" <sdtcontrols:CustomButton.Tag>\n" +
" <Controls0:MyExtension>\n" +
" <Controls0:MyExtension.MyProperty1>\n" +
" <Button />\n" +
" </Controls0:MyExtension.MyProperty1>\n" +
" </Controls0:MyExtension>\n" +
" </sdtcontrols:CustomButton.Tag>\n" +
"</sdtcontrols:CustomButton>\n";

AssertGridDesignerOutput(expectedXaml, grid.Context,
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
}

[Test]
public void PasteCustomControlUsingStaticResource()
{
DesignItem grid = CreateGridContextWithDesignSurface("<Button/>");

DesignItemProperty resProp = grid.Properties.GetProperty("Resources");
Assert.IsTrue(resProp.IsCollection);
DesignItem exampleClassItem = grid.Services.Component.RegisterComponentForDesigner(new ExampleClass());
exampleClassItem.Key = "res1";
resProp.CollectionElements.Add(exampleClassItem);

DesignItem myButton = grid.Services.Component.RegisterComponentForDesigner(new ICSharpCode.WpfDesign.Tests.Controls.CustomButton());
grid.Properties["Children"].CollectionElements.Add(myButton);

myButton.Properties[TextBox.TagProperty].SetValue(new StaticResourceExtension());
myButton.Properties[TextBox.TagProperty].Value.Properties["ResourceKey"].SetValue("res1");

// Verify xaml document to be copied
string expectedXaml = "<Grid.Resources>\n" +
" <Controls0:ExampleClass x:Key=\"res1\" />\n" +
"</Grid.Resources>\n" +
"<Button />\n" +
"<sdtcontrols:CustomButton Tag=\"{StaticResource ResourceKey=res1}\" />\n";

AssertGridDesignerOutput(expectedXaml, grid.Context,
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");

var xamlContext = grid.Context as XamlDesignContext;
Assert.IsNotNull(xamlContext);
xamlContext.XamlEditAction.Copy(new[] {myButton});

grid = CreateGridContextWithDesignSurface("<Button/>");

resProp = grid.Properties.GetProperty("Resources");
Assert.IsTrue(resProp.IsCollection);
exampleClassItem = grid.Services.Component.RegisterComponentForDesigner(new ExampleClass());
exampleClassItem.Key = "res1";
resProp.CollectionElements.Add(exampleClassItem);

xamlContext = grid.Context as XamlDesignContext;
Assert.IsNotNull(xamlContext);
var selection = grid.Services.Selection;
selection.SetSelectedComponents(new[] {grid});
xamlContext.XamlEditAction.Paste();

AssertGridDesignerOutput(expectedXaml, grid.Context,
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
}
}

public class MyExtension : MarkupExtension
{
public MyExtension()
{
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return null;
}

public object MyProperty1 { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ModelTestHelper
protected XamlDesignContext CreateContext(string xaml)
{
log = new StringBuilder();
XamlDesignContext context = new XamlDesignContext(new XmlTextReader(new StringReader(xaml)), new XamlLoadSettings());
XamlDesignContext context = new XamlDesignContext(new XmlTextReader(new StringReader(xaml)), CreateXamlLoadSettings());
/*context.Services.Component.ComponentRegistered += delegate(object sender, DesignItemEventArgs e) {
log.AppendLine("Register " + ItemIdentity(e.Item));
};
Expand Down Expand Up @@ -78,19 +78,7 @@ protected void AssertCanvasDesignerOutput(string expectedXaml, DesignContext con
expectedXaml.Replace("\r", "").Replace("\n", "\n ")
+ "\n</Canvas>";

StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
xmlWriter.Formatting = Formatting.Indented;
context.Save(xmlWriter);

string actualXaml = stringWriter.ToString().Replace("\r", "");;
if (expectedXaml != actualXaml) {
Debug.WriteLine("expected xaml:");
Debug.WriteLine(expectedXaml);
Debug.WriteLine("actual xaml:");
Debug.WriteLine(actualXaml);
}
Assert.AreEqual(expectedXaml, actualXaml);
AssertDesignerOutput(expectedXaml, context);
}

protected DesignItem CreateGridContext(string xaml)
Expand All @@ -107,16 +95,51 @@ protected DesignItem CreateGridContextWithDesignSurface(string xaml)
var surface = new DesignSurface();
var xamlWithGrid=@"<Grid xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" >
" + xaml + "</Grid>";
surface.LoadDesigner(new XmlTextReader(new StringReader(xamlWithGrid)), new XamlLoadSettings());
surface.LoadDesigner(new XmlTextReader(new StringReader(xamlWithGrid)), CreateXamlLoadSettings());
Assert.IsNotNull(surface.DesignContext.RootItem);
return surface.DesignContext.RootItem;
}

protected void AssertGridDesignerOutput(string expectedXaml, DesignContext context, params String[] additionalXmlns)
{
string gridStartTag = "<Grid xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";

foreach(string ns in additionalXmlns) {
gridStartTag += " " + ns;
}

expectedXaml = gridStartTag + ">\n" + expectedXaml.Trim();

expectedXaml =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n" +
expectedXaml.Replace("\r", "").Replace("\n", "\n ")
+ "\n</Grid>";

AssertDesignerOutput(expectedXaml, context);
}

static string ItemIdentity(DesignItem item)
{
return item.ComponentType.Name + " (" + item.GetHashCode() + ")";
}

protected void AssertDesignerOutput(string expectedXaml, DesignContext context)
{
StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
xmlWriter.Formatting = Formatting.Indented;
context.Save(xmlWriter);

string actualXaml = stringWriter.ToString().Replace("\r", "");;
if (expectedXaml != actualXaml) {
Debug.WriteLine("expected xaml:");
Debug.WriteLine(expectedXaml);
Debug.WriteLine("actual xaml:");
Debug.WriteLine(actualXaml);
}
Assert.AreEqual(expectedXaml, actualXaml);
}

protected void AssertLog(string expectedLog)
{
expectedLog = expectedLog.Replace("\r", "");
Expand All @@ -129,5 +152,10 @@ protected void AssertLog(string expectedLog)
}
Assert.AreEqual(expectedLog, actualLog);
}

protected virtual XamlLoadSettings CreateXamlLoadSettings()
{
return new XamlLoadSettings();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,39 @@ internal static object CreateObjectFromAttributeText(string valueText, Type targ
scope.OwnerDocument.GetTypeDescriptorContext(scope), valueText);
}

/// <summary>
/// Removes namespace attributes defined in the root from the specified node and all child nodes.
/// </summary>
static void RemoveRootNamespacesFromNodeAndChildNodes(XamlObject root, XmlNode node)
{
foreach (XmlNode childNode in node.ChildNodes) {
RemoveRootNamespacesFromNodeAndChildNodes(root, childNode);
}

if (node.Attributes != null) {
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
foreach (XmlAttribute attrib in node.Attributes) {
if (attrib.Name.StartsWith("xmlns:")) {
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
if (rootPrefix == null) {
//todo: check if we can add to root, (maybe same ns exists)
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
removeAttributes.Add(attrib);
}
else if (rootPrefix == attrib.Name.Substring("xmlns:".Length)) {
removeAttributes.Add(attrib);
}
}
else if (attrib.Name == "xmlns" && attrib.Value == XamlConstants.PresentationNamespace) {
removeAttributes.Add(attrib);
}
}
foreach (var removeAttribute in removeAttributes) {
node.Attributes.Remove(removeAttribute);
}
}
}

/// <summary>
/// Method use to parse a piece of Xaml.
/// </summary>
Expand All @@ -625,25 +658,8 @@ public static XamlObject ParseSnippet(XamlObject root, string xaml, XamlParserSe
}
if(xmlnsAttribute!=null)
element.Attributes.Remove(xmlnsAttribute);

//Remove namespace Attributes defined in the Xaml Root from the Pasted Snippet!
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
foreach (XmlAttribute attrib in element.Attributes) {
if (attrib.Name.StartsWith("xmlns:")) {
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
if (rootPrefix == null) {
//todo: check if we can add to root, (maybe same ns exists)
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
removeAttributes.Add(attrib);
} else if (rootPrefix == attrib.Name.Substring(6)) {
removeAttributes.Add(attrib);
}
}
}
foreach (var removeAttribute in removeAttributes) {
element.Attributes.Remove(removeAttribute);
}
//end remove

RemoveRootNamespacesFromNodeAndChildNodes(root, element);

XamlParser parser = new XamlParser();
parser.settings = settings;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,14 @@ public Type Resolve(string typeName)
typeNamespaceUri = GetNamespaceOfPrefix("");
typeLocalName = typeName;
}
if (string.IsNullOrEmpty(typeNamespaceUri))
if (string.IsNullOrEmpty(typeNamespaceUri)) {
var documentResolver = this.document.RootElement.ServiceProvider.Resolver;
if (documentResolver != null && documentResolver != this) {
return documentResolver.Resolve(typeName);
}

throw new XamlMarkupExtensionParseException("Unrecognized namespace prefix in type " + typeName);
}
return document.TypeFinder.GetType(typeNamespaceUri, typeLocalName);
}

Expand Down