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

Commit 2aa8ac7

Browse files
Merge pull request #78 from gumme/WpfDesignerPasteFixes2
Wpf designer paste fixes
2 parents aa1e6a4 + 410d444 commit 2aa8ac7

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
@@ -648,6 +648,39 @@ internal static object CreateObjectFromAttributeText(string valueText, Type targ
648648
scope.OwnerDocument.GetTypeDescriptorContext(scope), valueText);
649649
}
650650

651+
/// <summary>
652+
/// Removes namespace attributes defined in the root from the specified node and all child nodes.
653+
/// </summary>
654+
static void RemoveRootNamespacesFromNodeAndChildNodes(XamlObject root, XmlNode node)
655+
{
656+
foreach (XmlNode childNode in node.ChildNodes) {
657+
RemoveRootNamespacesFromNodeAndChildNodes(root, childNode);
658+
}
659+
660+
if (node.Attributes != null) {
661+
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
662+
foreach (XmlAttribute attrib in node.Attributes) {
663+
if (attrib.Name.StartsWith("xmlns:")) {
664+
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
665+
if (rootPrefix == null) {
666+
//todo: check if we can add to root, (maybe same ns exists)
667+
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
668+
removeAttributes.Add(attrib);
669+
}
670+
else if (rootPrefix == attrib.Name.Substring("xmlns:".Length)) {
671+
removeAttributes.Add(attrib);
672+
}
673+
}
674+
else if (attrib.Name == "xmlns" && attrib.Value == XamlConstants.PresentationNamespace) {
675+
removeAttributes.Add(attrib);
676+
}
677+
}
678+
foreach (var removeAttribute in removeAttributes) {
679+
node.Attributes.Remove(removeAttribute);
680+
}
681+
}
682+
}
683+
651684
/// <summary>
652685
/// Method use to parse a piece of Xaml.
653686
/// </summary>
@@ -668,25 +701,8 @@ public static XamlObject ParseSnippet(XamlObject root, string xaml, XamlParserSe
668701
}
669702
if(xmlnsAttribute!=null)
670703
element.Attributes.Remove(xmlnsAttribute);
671-
672-
//Remove namespace Attributes defined in the Xaml Root from the Pasted Snippet!
673-
List<XmlAttribute> removeAttributes = new List<XmlAttribute>();
674-
foreach (XmlAttribute attrib in element.Attributes) {
675-
if (attrib.Name.StartsWith("xmlns:")) {
676-
var rootPrefix = root.OwnerDocument.GetPrefixForNamespace(attrib.Value);
677-
if (rootPrefix == null) {
678-
//todo: check if we can add to root, (maybe same ns exists)
679-
root.OwnerDocument.XmlDocument.Attributes.Append((XmlAttribute)attrib.CloneNode(true));
680-
removeAttributes.Add(attrib);
681-
} else if (rootPrefix == attrib.Name.Substring(6)) {
682-
removeAttributes.Add(attrib);
683-
}
684-
}
685-
}
686-
foreach (var removeAttribute in removeAttributes) {
687-
element.Attributes.Remove(removeAttribute);
688-
}
689-
//end remove
704+
705+
RemoveRootNamespacesFromNodeAndChildNodes(root, element);
690706

691707
XamlParser parser = new XamlParser();
692708
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)