Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 1eed2fa

Browse files
author
gumme
committed
Removes namespace attributes from child nodes in the pasted snippet if they are already present in the root where the snippet is pasted.
Added a test "PasteCustomControlUsingMixedTypes" that failed before this fix.
1 parent f1da926 commit 1eed2fa

3 files changed

Lines changed: 141 additions & 34 deletions

File tree

src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/Designer/EditOperationTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System;
55
using System.Threading;
66
using System.Windows;
7+
using System.Windows.Controls;
8+
using System.Windows.Markup;
79

810
using ICSharpCode.WpfDesign.Designer.Xaml;
911
using ICSharpCode.WpfDesign.XamlDom;
@@ -14,6 +16,15 @@ namespace ICSharpCode.WpfDesign.Tests.Designer
1416
[TestFixture]
1517
public class EditOperationTests : ModelTestHelper
1618
{
19+
protected override XamlLoadSettings CreateXamlLoadSettings()
20+
{
21+
var settings = base.CreateXamlLoadSettings();
22+
23+
settings.TypeFinder.RegisterAssembly(typeof(NamespaceTests).Assembly);
24+
25+
return settings;
26+
}
27+
1728
Mutex mutex;
1829

1930
[TestFixtureSetUp]
@@ -151,5 +162,57 @@ public void PasteWhenIAddChildSelectedAndCannotAdd()
151162
Assert.AreEqual(_name, grid.ContentProperty.CollectionElements[3].Name);
152163
Assert.AreEqual(grid.ContentProperty.CollectionElements[3], selection.PrimarySelection);
153164
}
165+
166+
[Test]
167+
public void PasteCustomControlUsingMixedTypes()
168+
{
169+
DesignItem grid = CreateGridContextWithDesignSurface("<Button/>");
170+
DesignItem myButton = grid.Services.Component.RegisterComponentForDesigner(new ICSharpCode.WpfDesign.Tests.Controls.CustomButton());
171+
grid.Properties["Children"].CollectionElements.Add(myButton);
172+
173+
DesignItem extensionItem = grid.Services.Component.RegisterComponentForDesigner(new MyExtension());
174+
extensionItem.Properties["MyProperty1"].SetValue(new Button());
175+
myButton.Properties[ICSharpCode.WpfDesign.Tests.Controls.CustomButton.TagProperty].SetValue(extensionItem);
176+
177+
var xamlContext = grid.Context as XamlDesignContext;
178+
Assert.IsNotNull(xamlContext);
179+
xamlContext.XamlEditAction.Copy(new[] {myButton});
180+
181+
grid = CreateGridContextWithDesignSurface("<Button/>");
182+
xamlContext = grid.Context as XamlDesignContext;
183+
Assert.IsNotNull(xamlContext);
184+
var selection = grid.Services.Selection;
185+
selection.SetSelectedComponents(new[] {grid});
186+
xamlContext.XamlEditAction.Paste();
187+
188+
string expectedXaml = "<Button />\n" +
189+
"<sdtcontrols:CustomButton>\n" +
190+
" <sdtcontrols:CustomButton.Tag>\n" +
191+
" <Controls0:MyExtension>\n" +
192+
" <Controls0:MyExtension.MyProperty1>\n" +
193+
" <Button />\n" +
194+
" </Controls0:MyExtension.MyProperty1>\n" +
195+
" </Controls0:MyExtension>\n" +
196+
" </sdtcontrols:CustomButton.Tag>\n" +
197+
"</sdtcontrols:CustomButton>\n";
198+
199+
AssertGridDesignerOutput(expectedXaml, grid.Context,
200+
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
201+
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
202+
}
203+
}
204+
205+
public class MyExtension : MarkupExtension
206+
{
207+
public MyExtension()
208+
{
209+
}
210+
211+
public override object ProvideValue(IServiceProvider serviceProvider)
212+
{
213+
return null;
214+
}
215+
216+
public object MyProperty1 { get; set; }
154217
}
155218
}

src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/Designer/ModelTestHelper.cs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class ModelTestHelper
3030
protected XamlDesignContext CreateContext(string xaml)
3131
{
3232
log = new StringBuilder();
33-
XamlDesignContext context = new XamlDesignContext(new XmlTextReader(new StringReader(xaml)), new XamlLoadSettings());
33+
XamlDesignContext context = new XamlDesignContext(new XmlTextReader(new StringReader(xaml)), CreateXamlLoadSettings());
3434
/*context.Services.Component.ComponentRegistered += delegate(object sender, DesignItemEventArgs e) {
3535
log.AppendLine("Register " + ItemIdentity(e.Item));
3636
};
@@ -78,19 +78,7 @@ protected void AssertCanvasDesignerOutput(string expectedXaml, DesignContext con
7878
expectedXaml.Replace("\r", "").Replace("\n", "\n ")
7979
+ "\n</Canvas>";
8080

81-
StringWriter stringWriter = new StringWriter();
82-
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
83-
xmlWriter.Formatting = Formatting.Indented;
84-
context.Save(xmlWriter);
85-
86-
string actualXaml = stringWriter.ToString().Replace("\r", "");;
87-
if (expectedXaml != actualXaml) {
88-
Debug.WriteLine("expected xaml:");
89-
Debug.WriteLine(expectedXaml);
90-
Debug.WriteLine("actual xaml:");
91-
Debug.WriteLine(actualXaml);
92-
}
93-
Assert.AreEqual(expectedXaml, actualXaml);
81+
AssertDesignerOutput(expectedXaml, context);
9482
}
9583

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

103+
protected void AssertGridDesignerOutput(string expectedXaml, DesignContext context, params String[] additionalXmlns)
104+
{
105+
string gridStartTag = "<Grid xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"";
106+
107+
foreach(string ns in additionalXmlns) {
108+
gridStartTag += " " + ns;
109+
}
110+
111+
expectedXaml = gridStartTag + ">\n" + expectedXaml.Trim();
112+
113+
expectedXaml =
114+
"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n" +
115+
expectedXaml.Replace("\r", "").Replace("\n", "\n ")
116+
+ "\n</Grid>";
117+
118+
AssertDesignerOutput(expectedXaml, context);
119+
}
120+
115121
static string ItemIdentity(DesignItem item)
116122
{
117123
return item.ComponentType.Name + " (" + item.GetHashCode() + ")";
118124
}
119125

126+
protected void AssertDesignerOutput(string expectedXaml, DesignContext context)
127+
{
128+
StringWriter stringWriter = new StringWriter();
129+
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
130+
xmlWriter.Formatting = Formatting.Indented;
131+
context.Save(xmlWriter);
132+
133+
string actualXaml = stringWriter.ToString().Replace("\r", "");;
134+
if (expectedXaml != actualXaml) {
135+
Debug.WriteLine("expected xaml:");
136+
Debug.WriteLine(expectedXaml);
137+
Debug.WriteLine("actual xaml:");
138+
Debug.WriteLine(actualXaml);
139+
}
140+
Assert.AreEqual(expectedXaml, actualXaml);
141+
}
142+
120143
protected void AssertLog(string expectedLog)
121144
{
122145
expectedLog = expectedLog.Replace("\r", "");
@@ -129,5 +152,10 @@ protected void AssertLog(string expectedLog)
129152
}
130153
Assert.AreEqual(expectedLog, actualLog);
131154
}
155+
156+
protected virtual XamlLoadSettings CreateXamlLoadSettings()
157+
{
158+
return new XamlLoadSettings();
159+
}
132160
}
133161
}

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

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,39 @@ internal static object CreateObjectFromAttributeText(string valueText, Type targ
603603
scope.OwnerDocument.GetTypeDescriptorContext(scope), valueText);
604604
}
605605

606+
/// <summary>
607+
/// Removes namespace attributes defined in the root from the specified node and all child nodes.
608+
/// </summary>
609+
static void RemoveRootNamespacesFromNodeAndChildNodes(XamlObject root, XmlNode node)
610+
{
611+
foreach (XmlNode childNode in node.ChildNodes) {
612+
RemoveRootNamespacesFromNodeAndChildNodes(root, childNode);
613+
}
614+
615+
if (node.Attributes != null) {
616+
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
617+
foreach (XmlAttribute attrib in node.Attributes) {
618+
if (attrib.Name.StartsWith("xmlns:")) {
619+
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
620+
if (rootPrefix == null) {
621+
//todo: check if we can add to root, (maybe same ns exists)
622+
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
623+
removeAttributes.Add(attrib);
624+
}
625+
else if (rootPrefix == attrib.Name.Substring("xmlns:".Length)) {
626+
removeAttributes.Add(attrib);
627+
}
628+
}
629+
else if (attrib.Name == "xmlns" && attrib.Value == XamlConstants.PresentationNamespace) {
630+
removeAttributes.Add(attrib);
631+
}
632+
}
633+
foreach (var removeAttribute in removeAttributes) {
634+
node.Attributes.Remove(removeAttribute);
635+
}
636+
}
637+
}
638+
606639
/// <summary>
607640
/// Method use to parse a piece of Xaml.
608641
/// </summary>
@@ -623,25 +656,8 @@ public static XamlObject ParseSnippet(XamlObject root, string xaml, XamlParserSe
623656
}
624657
if(xmlnsAttribute!=null)
625658
element.Attributes.Remove(xmlnsAttribute);
626-
627-
//Remove namespace Attributes defined in the Xaml Root from the Pasted Snippet!
628-
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
629-
foreach (XmlAttribute attrib in element.Attributes) {
630-
if (attrib.Name.StartsWith("xmlns:")) {
631-
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
632-
if (rootPrefix == null) {
633-
//todo: check if we can add to root, (maybe same ns exists)
634-
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
635-
removeAttributes.Add(attrib);
636-
} else if (rootPrefix == attrib.Name.Substring(6)) {
637-
removeAttributes.Add(attrib);
638-
}
639-
}
640-
}
641-
foreach (var removeAttribute in removeAttributes) {
642-
element.Attributes.Remove(removeAttribute);
643-
}
644-
//end remove
659+
660+
RemoveRootNamespacesFromNodeAndChildNodes(root, element);
645661

646662
XamlParser parser = new XamlParser();
647663
parser.settings = settings;

0 commit comments

Comments
 (0)