|
Hello,
I have written a control. This control has an embedded component property. Example:
public MyComponent:Component { .. // some properties here }
public class MyControl:Control { public MyComponent embedded { get{...} set{...} } }
The problem is now, that the changes to the embedded control property are not automatically serialized by the designer. When I close the designer and reopen it, all the changes are lost. I want to achieve the same behaviour like the MainMenu class. For every MenuItem, that I add to the mainmenu the designer serializes this item in the InitializeComponent-method. Does anyone know, how this works?
Thanks
|
| MigrationUser 1 Sunday, January 30, 2005 5:21 AM |
<b>[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]</b> public MyComponent:Component { .. // some properties here } |
| MigrationUser 1 Monday, January 31, 2005 5:02 AM |
Hello joeycalisay,
thank you for your reply. I tried to do this before and it does'nt work. I cannot adapt this attribute to the MyComponent class. The compiler returns an error, that says, that this attribute cannot be adapted to classes, but only to properties and methods. If I adapt this attribute to the property in my Control class, nothing is serialized. I really don't know, how to make it work.
Greets
|
| MigrationUser 1 Monday, January 31, 2005 11:09 AM |
my mistake, you're right, it should have been attached to the property.
anyway, i re-read this post this morning. if you already have developed the component, you can just drag it into the designer surface of your control from the toolbox and it will be automatically added to your control and be serialized as part of its InitializeComponent method. Do you really need it to be a property of your control? |
| MigrationUser 1 Wednesday, February 02, 2005 12:36 AM |
Adding the DesignerSerializationVisibility attribute to the Embedded property results in the component serializing just fine in my environment. If the property is initialised with a default component then the serialized component is different to standard serialization but it still works. I get serialization something like this in that case:
// //myControl1 // // //myControl1.myComponent // this.myControl1.myComponent.SomeProperty = blah; this.myControl1.Name = "myControl1"
However, I believe what you are after is a Collection of components, and this can be achieved with the following code. you will need to add a reference to System.Design.dll
using System; using System.ComponentModel; using System.Windows.Forms; using System.Drawing.Design; using System.ComponentModel.Design; using System.Collections;
public class MyControl:Control { private ArrayList embedded = new ArrayList();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [Editor(typeof(MyComponentCollectionEditor), typeof(UITypeEditor))] public ArrayList Embedded { get{return embedded;} }
internal class MyComponentCollectionEditor : CollectionEditor { public MyComponentCollectionEditor(System.Type type): base(type) { } protected override Type CreateCollectionItemType() { return typeof(MyComponent); } } }
public class MyComponent:Component { //Properties here }
|
| MigrationUser 1 Wednesday, February 02, 2005 8:19 AM |
thanks for clarifying that Mr. Doherty... |
| MigrationUser 1 Wednesday, February 02, 2005 7:29 PM |
Thank you Mick,
i can't get this thing to work. I don't want to do it with a collection. The first example you posted is what I want to have. Can you post the whole code for the control and the component please?
|
| MigrationUser 1 Friday, February 11, 2005 6:08 AM |
I interpreted the following phrase as "I want a Collection of Components". ########################################################### "I want to achieve the same behaviour like the MainMenu class. For every MenuItem, that I add to the mainmenu the designer serializes this item in the InitializeComponent-method. " ###########################################################
I just spent an hour trying to get this to work again, I couldn't understand why it was so simple last time I tried and this time I couldn't get it to work.
It turns out that if the embedded property is readonly then it will serialize, just fine. Making it readonly does not mean you cant change the components properties, you just can't change it for another component.
public class MyControl:Control { private MyComponent embedded = new MyComponent(); [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public MyComponent Embedded { get{return embedded;} } }
public class MyComponent:Component { private String someProperty = "blah"; public String SomeProperty { get{return someProperty;} set{someProperty = value;} } }
|
| MigrationUser 1 Friday, February 11, 2005 1:23 PM |
Hi Mick,
ok, that was the problem. But what, if I want to change the embedded component instance settings without having to change every property one by one. I just want to write something like this.
MyComponent embedded2 = new MyComponent(); // ... change some properties of embedded2 here MyControl.Embedded = embedded2;
This is not possible, if I have to declare the property as read-only. And now I have another problem. The serialization works, but it seems to work not correctly. I get something like this, in the InitializeComponent()-Method:
// // myControl1 // this.myControl1.BackColor = System.Drawing.SystemColors.ControlLightLight; this.myControl1.FocusColor = System.Drawing.SystemColors.ControlDarkDark; this.myControl1.ForeColor = System.Drawing.SystemColors.ControlDark; // // myControl1.Embedded // this.myControl1.Embedded.Color = System.Drawing.SystemColors.ControlDarkDark; this.myControl1.Embedded.Cursor = System.Windows.Forms.Cursors.Hand; this.myControl1.Embedded.Width = 3; this.myControl1.InvertedUse = false; this.myControl1.Name = "simpleFader1"; this.myControl1.Size = new System.Drawing.Size(184, 504); this.myControl1.TabIndex = 0; this.myControl1.Text = "myControl1";
As you see, there are two sections. One for the control properties and another for the component properties. But when you take a closer look, you can see, that there are some control properties in the section of embedded component. It seems not to work very well. It's a strange behaviour, isn't it?
|
| MigrationUser 1 Sunday, February 13, 2005 6:36 AM |
The result was expected. Your embedded component is instantiated by your control (runtime or designtime), Do you really want to reinstantiate it this way on each form that uses your control:
MyComponent embedded2 = new MyComponent(); // ... change some properties of embedded2 here MyControl.Embedded = embedded2;
What for? |
| MigrationUser 1 Monday, February 14, 2005 5:45 AM |
I expect that you actually see the Serialization as below. The reason it serializes like this is that the properties are serialized Alphabetically. Change the Embedded properties name to Associated and it will be serialized as you expected to see it.
// // myControl1 // this.myControl1.BackColor = System.Drawing.SystemColors.ControlLightLight; // // myControl1.Embedded // this.myControl1.Embedded.Color = System.Drawing.SystemColors.ControlDarkDark; this.myControl1.Embedded.Cursor = System.Windows.Forms.Cursors.Hand; this.myControl1.Embedded.Width = 3; this.myControl1.FocusColor = System.Drawing.SystemColors.ControlDarkDark; this.myControl1.ForeColor = System.Drawing.SystemColors.ControlDark; this.myControl1.InvertedUse = false;
As for changing the component, are you talking about changing it at design time? If so then the simplist solution is to make the property Read/Write and don't supply a Default component. You can then just drop components on the form and select one from the Embedded properties dropdown list. If you want to have a default component then you will need to create a Designer for your control and have it create the Embedded component. If you mean changing the settings at runtime then I would simply create a structure to store settings and create a method to apply the settings (although you could do the same with a predifined component instead of a structure):
private struct embeddedProperties { public Color color; public Cursor cursor; public int width; public embeddedProperties(MyComponent e) { color = e.Color; cursor = e.Cursor; width = e.Width; } }
embeddedProperties embedded1; embeddedProperties embedded2;
private void Form1_Load(object sender, System.EventArgs e) { embedded1 = new embeddedProperties(this.myControl1.Embedded); embedded2 = new embeddedProperties(this.myControl1.Embedded); embedded2.color = Color.Turquoise; embedded2.cursor = Cursors.Hand; }
private void SetEmbedded(embeddedProperties e) { this.myControl1.Embedded.Color = e.color; this.myControl1.Embedded.Cursor = e.cursor; this.myControl1.Embedded.Width = e.width; }
|
| MigrationUser 1 Monday, February 14, 2005 8:53 AM |
Nope, I don't want the designer to reinstantiate the embedded component. I want to change the instance of the embedded component by myself. If e.g. the embedded component represents a scale with a maximum, a minimum, a tick frequency, ..., and my control is a slider control for example. Now I want to write an application that is able to show a slider and switch between different scales for this slider. If I have 10 scales I can simply save the scale instances in an array in my application and when the user switches between the scales I can simply replace the old scale by the new one:
mySlider1.EmbeddedScale = myScales[i];
If this is not possible I have to do something like this:
mySlider1.EmbeddedScale.Maximum = myScales[i].Maximum; mySlider1.EmbeddedScale.Minimum = myScales[i].Minimum; mySlider1.EmbeddedScale.TickFrequency = myScales[i].TickFrequency; ....
It should be possible to serialize embedded component properties when the embedded component property is not readonly. Why isn't it possible? I can't find a plausible explanation. |
| MigrationUser 1 Monday, February 14, 2005 10:13 AM |
Don't use Component -- derive from object, and use a TypeDescriptor, with a conversion to an InstanceDescriptor to support serialization. You also will need CreateInstanceSupported and CreateInstance implementations. Then you can pop up a custom UITypeEditor to edit this property, if you wish. |
| MigrationUser 1 Tuesday, February 15, 2005 3:33 PM |
Hi Frank,
but that's more than I want to do. I simply want to change some properties of the embedded component through the designer. And the property which is used access the embedded property should not be readonly. I can't believe that there is no simple solution.
|
| MigrationUser 1 Wednesday, February 16, 2005 3:02 AM |
For a simple runtime workaround just add this code to the MyControl class:
public void SetEmbedded(MyComponent myComponent) { embedded = myComponent }
|
| MigrationUser 1 Thursday, February 17, 2005 6:42 AM |
OK,
this is a good idea for a workaround. But I can't believe it's not possible to create a writable property. |
| MigrationUser 1 Friday, February 18, 2005 6:02 AM |
OK, this can be used to make the property writable, although I would like to have a solution with a writable property. But the problem with the wrong order is still there:
// // myControl1 // this.myControl1.BackColor = System.Drawing.SystemColors.ControlLightLight; this.myControl1.BorderColor = System.Drawing.SystemColors.WindowFrame; this.myControl1.BorderWidth = 3; // // myControl1.Embedded // this.myControl1.Embedded.Color = System.Drawing.SystemColors.ControlDarkDark; this.myControl1.Embedded.Cursor = System.Windows.Forms.Cursors.Hand; this.myControl1.Embedded.Width = 3; this.myControl1.InvertedUse = false; this.myControl1.Location = new System.Drawing.Point(72, 16); this.myControl1.Name = "simpleFader1"; this.myControl1.Size = new System.Drawing.Size(24, 240); this.myControl1.TabIndex = 0; this.myControl1.Text = "simpleFader1"; this.myControl1.Value = 5;
As you see, the information is correctly serialized in the InitializeComponent method of the form. There are two sections. One for the control and another for the embedded component. The problem is that all the properties of the control and the embedded property are serialized in alphabetical order, and all the control properties that begin with a character bigger than 'E' are serialized underneath the section of the embedded component. I don't understand this strange behaviour.
Any ideas? |
| MigrationUser 1 Friday, February 18, 2005 8:14 AM |