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

Commit cd29a15

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 b5b1573 commit cd29a15

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]
@@ -204,5 +215,57 @@ public void PasteSameElementMultipleTimesCheckCopiesNames()
204215
Assert.IsNotNull(nameScope.FindName(_name + "_Copy3"));
205216
Assert.IsNull(nameScope.FindName(_name + "_Copy4"));
206217
}
218+
219+
[Test]
220+
public void PasteCustomControlUsingMixedTypes()
221+
{
222+
DesignItem grid = CreateGridContextWithDesignSurface("<Button/>");
223+
DesignItem myButton = grid.Services.Component.RegisterComponentForDesigner(new ICSharpCode.WpfDesign.Tests.Controls.CustomButton());
224+
grid.Properties["Children"].CollectionElements.Add(myButton);
225+
226+
DesignItem extensionItem = grid.Services.Component.RegisterComponentForDesigner(new MyExtension());
227+
extensionItem.Properties["MyProperty1"].SetValue(new Button());
228+
myButton.Properties[ICSharpCode.WpfDesign.Tests.Controls.CustomButton.TagProperty].SetValue(extensionItem);
229+
230+
var xamlContext = grid.Context as XamlDesignContext;
231+
Assert.IsNotNull(xamlContext);
232+
xamlContext.XamlEditAction.Copy(new[] {myButton});
233+
234+
grid = CreateGridContextWithDesignSurface("<Button/>");
235+
xamlContext = grid.Context as XamlDesignContext;
236+
Assert.IsNotNull(xamlContext);
237+
var selection = grid.Services.Selection;
238+
selection.SetSelectedComponents(new[] {grid});
239+
xamlContext.XamlEditAction.Paste();
240+
241+
string expectedXaml = "<Button />\n" +
242+
"<sdtcontrols:CustomButton>\n" +
243+
" <sdtcontrols:CustomButton.Tag>\n" +
244+
" <Controls0:MyExtension>\n" +
245+
" <Controls0:MyExtension.MyProperty1>\n" +
246+
" <Button />\n" +
247+
" </Controls0:MyExtension.MyProperty1>\n" +
248+
" </Controls0:MyExtension>\n" +
249+
" </sdtcontrols:CustomButton.Tag>\n" +
250+
"</sdtcontrols:CustomButton>\n";
251+
252+
AssertGridDesignerOutput(expectedXaml, grid.Context,
253+
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
254+
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
255+
}
256+
}
257+
258+
public class MyExtension : MarkupExtension
259+
{
260+
public MyExtension()
261+
{
262+
}
263+
264+
public override object ProvideValue(IServiceProvider serviceProvider)
265+
{
266+
return null;
267+
}
268+
269+
public object MyProperty1 { get; set; }
207270
}
208271
}

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
@@ -605,6 +605,39 @@ internal static object CreateObjectFromAttributeText(string valueText, Type targ
605605
scope.OwnerDocument.GetTypeDescriptorContext(scope), valueText);
606606
}
607607

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

648664
XamlParser parser = new XamlParser();
649665
parser.settings = settings;

0 commit comments

Comments
 (0)