diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs
index a2c85c2172..98fe34e549 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs
@@ -24,6 +24,8 @@ namespace ICSharpCode.PythonBinding
///
public class PythonDesignerComponent
{
+ delegate void AppendCollectionContent(PythonCodeBuilder codeBuilder, object item, int count);
+
IComponent component;
static readonly Attribute[] notDesignOnlyFilter = new Attribute[] { DesignOnlyAttribute.No };
static readonly DesignerSerializationVisibility[] notHiddenDesignerVisibility = new DesignerSerializationVisibility[] { DesignerSerializationVisibility.Content, DesignerSerializationVisibility.Visible };
@@ -208,19 +210,14 @@ namespace ICSharpCode.PythonBinding
///
public virtual void AppendCreateInstance(PythonCodeBuilder codeBuilder)
{
+ string parameters = String.Empty;
if (HasIContainerConstructor()) {
codeBuilder.InsertCreateComponentsContainer();
- AppendCreateInstance(codeBuilder, "self._components");
- } else {
- AppendComponentCreation(codeBuilder, component);
- }
- }
-
- public void AppendCreateInstance(PythonCodeBuilder codeBuilder, string parameters)
- {
+ parameters = "self._components";
+ }
AppendComponentCreation(codeBuilder, component, parameters);
}
-
+
///
/// Appends the code to create the child components.
///
@@ -420,12 +417,15 @@ namespace ICSharpCode.PythonBinding
{
AppendComponentCreation(codeBuilder, component, String.Empty);
}
-
+
///
/// Appends the code to create the specified IComponent
///
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component, string parameters)
{
+ if (ShouldAppendCollectionContent) {
+ AppendForEachCollectionContent(codeBuilder, component, AppendCollectionContentCreation);
+ }
codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "(" + parameters + ")");
}
@@ -471,6 +471,24 @@ namespace ICSharpCode.PythonBinding
}
}
+ ///
+ /// Looks for any collections that have objects that should be created as local variables
+ /// in the InitializeComponent method.
+ ///
+ public void AppendCollectionContentCreation(PythonCodeBuilder codeBuilder, object item, int count)
+ {
+ AppendCreateInstance(codeBuilder, item, count, new object[0]);
+ }
+
+ ///
+ /// Looks for any collections that have objects that will have been added as local variables
+ /// and appends their property values.
+ ///
+ public void AppendCollectionContentProperties(PythonCodeBuilder codeBuilder, object item, int count)
+ {
+ AppendProperties(codeBuilder, GetVariableName(item, count), item);
+ }
+
///
/// Gets the variable name for the specified type.
///
@@ -501,7 +519,6 @@ namespace ICSharpCode.PythonBinding
///
public static void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor, bool reverse)
{
- IComponent component = propertyOwner as IComponent;
ICollection collectionProperty = propertyDescriptor.GetValue(propertyOwner) as ICollection;
if (collectionProperty != null) {
MethodInfo addRangeMethod = GetAddRangeSerializationMethod(collectionProperty);
@@ -529,7 +546,7 @@ namespace ICSharpCode.PythonBinding
///
public void AppendProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj, PropertyDescriptor propertyDescriptor)
{
- object propertyValue = propertyDescriptor.GetValue(obj);
+ object propertyValue = propertyDescriptor.GetValue(obj);
ExtenderProvidedPropertyAttribute extender = GetExtenderAttribute(propertyDescriptor);
if (extender != null) {
AppendExtenderProperty(codeBuilder, propertyOwnerName, extender, propertyDescriptor, propertyValue);
@@ -601,6 +618,10 @@ namespace ICSharpCode.PythonBinding
///
public void AppendProperties(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj)
{
+ if (ShouldAppendCollectionContent) {
+ AppendForEachCollectionContent(codeBuilder, obj, AppendCollectionContentProperties);
+ }
+
foreach (PropertyDescriptor property in GetSerializableProperties(obj)) {
if (!IgnoreProperty(property)) {
AppendProperty(codeBuilder, propertyOwnerName, obj, property);
@@ -781,6 +802,10 @@ namespace ICSharpCode.PythonBinding
return false;
}
+ protected virtual bool ShouldAppendCollectionContent {
+ get { return true; }
+ }
+
static bool HasSitedComponents(PythonDesignerComponent[] components)
{
foreach (PythonDesignerComponent component in components) {
@@ -899,5 +924,27 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
+
+ ///
+ /// Calls the AppendCollectionContent method for every item in all collections that need their content
+ /// serialized.
+ ///
+ void AppendForEachCollectionContent(PythonCodeBuilder codeBuilder, object component, AppendCollectionContent appendCollectionContent)
+ {
+ foreach (PropertyDescriptor propertyDescriptor in GetSerializableContentProperties(component)) {
+ ICollection collection = propertyDescriptor.GetValue(component) as ICollection;
+ if (collection != null) {
+ int count = 1;
+ foreach (object item in collection) {
+ if (item is IComponent) {
+ // Ignore.
+ } else {
+ appendCollectionContent(codeBuilder, item, count);
+ }
+ ++count;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs
index 02de20489b..7741cc31c9 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs
@@ -58,6 +58,10 @@ namespace ICSharpCode.PythonBinding
AppendListViewGroupProperties(codeBuilder);
AppendComponentProperties(codeBuilder, true, false);
}
+
+ protected override bool ShouldAppendCollectionContent {
+ get { return false; }
+ }
///
/// Gets the parameters to the ListViewItem constructor.
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs
index 3d73cddac0..ee109bd7c3 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs
@@ -30,6 +30,10 @@ namespace ICSharpCode.PythonBinding
base.AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor);
}
}
+
+ protected override bool ShouldAppendCollectionContent {
+ get { return false; }
+ }
bool IsStylesProperty(string name)
{
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs
index 389e17a0e1..dd441ea589 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs
@@ -51,6 +51,10 @@ namespace ICSharpCode.PythonBinding
AppendComponentProperties(codeBuilder, true, false);
}
+ protected override bool ShouldAppendCollectionContent {
+ get { return false; }
+ }
+
void AppendCreateInstance(PythonCodeBuilder codeBuilder, List nodes)
{
object[] parameters = new object[0];
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs
new file mode 100644
index 0000000000..1eb07615d2
--- /dev/null
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs
@@ -0,0 +1,89 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.ComponentModel.Design.Serialization;
+using System.Drawing;
+using System.Windows.Forms;
+using ICSharpCode.PythonBinding;
+using NUnit.Framework;
+using PythonBinding.Tests.Utils;
+
+namespace PythonBinding.Tests.Designer
+{
+ ///
+ /// Tests that a custom collection class generates the correct code.
+ /// The collection class should be a property of a custom component or user control
+ /// and it should be marked with DesignerSerializationVisibility.Content.
+ ///
+ [TestFixture]
+ public class GenerateCustomCollectionItemsTestFixture
+ {
+ string generatedPythonCode;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ using (DesignSurface designSurface = new DesignSurface(typeof(Form))) {
+ IDesignerHost host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
+ IEventBindingService eventBindingService = new MockEventBindingService(host);
+ Form form = (Form)host.RootComponent;
+ form.ClientSize = new Size(200, 300);
+
+ PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(form);
+ PropertyDescriptor namePropertyDescriptor = descriptors.Find("Name", false);
+ namePropertyDescriptor.SetValue(form, "MainForm");
+
+ // Add custom control
+ CustomUserControl userControl = (CustomUserControl)host.CreateComponent(typeof(CustomUserControl), "userControl1");
+ userControl.Location = new Point(0, 0);
+ userControl.ClientSize = new Size(200, 100);
+ userControl.FooItems.Add(new FooItem("aa"));
+ userControl.FooItems.Add(new FooItem("bb"));
+ form.Controls.Add(userControl);
+
+ PythonControl pythonForm = new PythonControl(" ");
+ generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form);
+ }
+ }
+
+ [Test]
+ public void GeneratedCode()
+ {
+ string expectedCode = "def InitializeComponent(self):\r\n" +
+ " fooItem1 = PythonBinding.Tests.Utils.FooItem()\r\n" +
+ " fooItem2 = PythonBinding.Tests.Utils.FooItem()\r\n" +
+ " self._userControl1 = PythonBinding.Tests.Utils.CustomUserControl()\r\n" +
+ " self.SuspendLayout()\r\n" +
+ " # \r\n" +
+ " # userControl1\r\n" +
+ " # \r\n" +
+ " fooItem1.Text = \"aa\"\r\n" +
+ " fooItem2.Text = \"bb\"\r\n" +
+ " self._userControl1.FooItems.AddRange(System.Array[PythonBinding.Tests.Utils.FooItem](\r\n" +
+ " [fooItem1,\r\n" +
+ " fooItem2]))\r\n" +
+ " self._userControl1.Location = System.Drawing.Point(0, 0)\r\n" +
+ " self._userControl1.Name = \"userControl1\"\r\n" +
+ " self._userControl1.Size = System.Drawing.Size(200, 100)\r\n" +
+ " self._userControl1.TabIndex = 0\r\n" +
+ " # \r\n" +
+ " # MainForm\r\n" +
+ " # \r\n" +
+ " self.ClientSize = System.Drawing.Size(200, 300)\r\n" +
+ " self.Controls.Add(self._userControl1)\r\n" +
+ " self.Name = \"MainForm\"\r\n" +
+ " self.ResumeLayout(False)\r\n" +
+ " self.PerformLayout()\r\n";
+
+ Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode);
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
index d5a3c836ba..51bc41b782 100644
--- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
@@ -189,6 +189,7 @@
+
@@ -327,6 +328,7 @@
+
@@ -337,6 +339,7 @@
+
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs
new file mode 100644
index 0000000000..d50f32e673
--- /dev/null
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs
@@ -0,0 +1,27 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+
+namespace PythonBinding.Tests.Utils
+{
+ public class CustomUserControl : UserControl
+ {
+ FooItemCollection fooItems = new FooItemCollection();
+
+ public CustomUserControl()
+ {
+ }
+
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
+ public FooItemCollection FooItems {
+ get { return fooItems; }
+ }
+ }
+}
diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs
new file mode 100644
index 0000000000..40ad8cc321
--- /dev/null
+++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs
@@ -0,0 +1,46 @@
+//
+//
+//
+//
+// $Revision$
+//
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace PythonBinding.Tests.Utils
+{
+ public class FooItem
+ {
+ string text = String.Empty;
+
+ public FooItem()
+ {
+ }
+
+ public FooItem(string text)
+ {
+ this.text = text;
+ }
+
+ public string Text {
+ get { return text; }
+ set { text = value; }
+ }
+ }
+
+ public class FooItemCollection : Collection
+ {
+ public FooItemCollection()
+ {
+ }
+
+ public void AddRange(FooItem[] items)
+ {
+ foreach (FooItem item in items) {
+ Add(item);
+ }
+ }
+ }
+}