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

Commit 3e27053

Browse files
author
gumme
committed
Merge remote-tracking branch 'origin/WpfDesignerPasteFixes'
Conflicts: src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Tests/Designer/EditOperationTests.cs
2 parents 8bf2a76 + 0563174 commit 3e27053

4 files changed

Lines changed: 199 additions & 35 deletions

File tree

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

Lines changed: 114 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,108 @@ 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+
[Test]
258+
public void PasteCustomControlUsingStaticResource()
259+
{
260+
DesignItem grid = CreateGridContextWithDesignSurface("<Button/>");
261+
262+
DesignItemProperty resProp = grid.Properties.GetProperty("Resources");
263+
Assert.IsTrue(resProp.IsCollection);
264+
DesignItem exampleClassItem = grid.Services.Component.RegisterComponentForDesigner(new ExampleClass());
265+
exampleClassItem.Key = "res1";
266+
resProp.CollectionElements.Add(exampleClassItem);
267+
268+
DesignItem myButton = grid.Services.Component.RegisterComponentForDesigner(new ICSharpCode.WpfDesign.Tests.Controls.CustomButton());
269+
grid.Properties["Children"].CollectionElements.Add(myButton);
270+
271+
myButton.Properties[TextBox.TagProperty].SetValue(new StaticResourceExtension());
272+
myButton.Properties[TextBox.TagProperty].Value.Properties["ResourceKey"].SetValue("res1");
273+
274+
// Verify xaml document to be copied
275+
string expectedXaml = "<Grid.Resources>\n" +
276+
" <Controls0:ExampleClass x:Key=\"res1\" />\n" +
277+
"</Grid.Resources>\n" +
278+
"<Button />\n" +
279+
"<sdtcontrols:CustomButton Tag=\"{StaticResource ResourceKey=res1}\" />\n";
280+
281+
AssertGridDesignerOutput(expectedXaml, grid.Context,
282+
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
283+
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
284+
285+
var xamlContext = grid.Context as XamlDesignContext;
286+
Assert.IsNotNull(xamlContext);
287+
xamlContext.XamlEditAction.Copy(new[] {myButton});
288+
289+
grid = CreateGridContextWithDesignSurface("<Button/>");
290+
291+
resProp = grid.Properties.GetProperty("Resources");
292+
Assert.IsTrue(resProp.IsCollection);
293+
exampleClassItem = grid.Services.Component.RegisterComponentForDesigner(new ExampleClass());
294+
exampleClassItem.Key = "res1";
295+
resProp.CollectionElements.Add(exampleClassItem);
296+
297+
xamlContext = grid.Context as XamlDesignContext;
298+
Assert.IsNotNull(xamlContext);
299+
var selection = grid.Services.Selection;
300+
selection.SetSelectedComponents(new[] {grid});
301+
xamlContext.XamlEditAction.Paste();
302+
303+
AssertGridDesignerOutput(expectedXaml, grid.Context,
304+
"xmlns:Controls0=\"clr-namespace:ICSharpCode.WpfDesign.Tests.Designer;assembly=ICSharpCode.WpfDesign.Tests\"",
305+
"xmlns:sdtcontrols=\"http://sharpdevelop.net/WpfDesign/Tests/Controls\"");
306+
}
307+
}
308+
309+
public class MyExtension : MarkupExtension
310+
{
311+
public MyExtension()
312+
{
313+
}
314+
315+
public override object ProvideValue(IServiceProvider serviceProvider)
316+
{
317+
return null;
318+
}
319+
320+
public object MyProperty1 { get; set; }
207321
}
208322
}

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;

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,14 @@ public Type Resolve(string typeName)
5757
typeNamespaceUri = GetNamespaceOfPrefix("");
5858
typeLocalName = typeName;
5959
}
60-
if (string.IsNullOrEmpty(typeNamespaceUri))
60+
if (string.IsNullOrEmpty(typeNamespaceUri)) {
61+
var documentResolver = this.document.RootElement.ServiceProvider.Resolver;
62+
if (documentResolver != null && documentResolver != this) {
63+
return documentResolver.Resolve(typeName);
64+
}
65+
6166
throw new XamlMarkupExtensionParseException("Unrecognized namespace prefix in type " + typeName);
67+
}
6268
return document.TypeFinder.GetType(typeNamespaceUri, typeLocalName);
6369
}
6470

0 commit comments

Comments
 (0)