Hi Sorin,
Thank you for your feedback.
I am trying to implement a custom collection editor for the inner
DataGridView columns within a UserControl. The custom collection editor is
derived from CollectionEditor. The following is the code of the custom
collection editor.
using System.ComponentModel.Design;
using System.Windows.Forms;
class MyCollectionEditor:CollectionEditor
{
public MyCollectionEditor(Type type)
: base(type)
{ }
protected override Type CreateCollectionItemType()
{
return typeof(DataGridViewColumn);
}
protected override Type[] CreateNewItemTypes()
{
Type[] types = new Type[] { typeof(DataGridViewTextBoxColumn),
typeof(DataGridViewComboBoxColumn),
typeof(DataGridViewCheckBoxColumn),
typeof(DataGridViewButtonColumn),
typeof(DataGridViewImageColumn),
typeof(DataGridViewLinkColumn)};
return types;
}
protected override object CreateInstance(Type itemType)
{
DataGridViewColumn column =
itemType.GetConstructor(Type.EmptyTypes).Invoke(null) as
DataGridViewColumn;
return column;
}
}
We need to add an EditorAttribute on the inner DataGridView columns
property in the UserControl.
public partial class UserControl1 : UserControl
{
[Editor(typeof(MyCollectionEditor),typeof(UITypeEditor))]
public DataGridViewColumnCollection InnerDGVColumns
{
get { return this.dataGridView1.Columns; }
}
}
Thus, I could edit the columns for the DataGridView within the UserControl
at design-time. However, the problem is that the designer doesn't serialize
the code of the columns of the DataGridView after I add some columns into
the DataGridView at design-time.
I am thinking of using CodeDomSerializer to get the columns serialized
correctly. Unfortunately, I haven't worked it out yet.
I will go on researching on this and will get it back to you ASAP. I
appreciate your patience.
Sincerely,
Linda Liu
Microsoft Online Community Support
==============================================
Can you send me the sample project.
(E-Mail Removed)
"Linda Liu [MSFT]" wrote:
> Hi Sorin,
>
> Sorry for my delayed response. I have spent much time researching on how to
> serialize the inner DataGridView's columns and finally I got it!
>
> We need to implement a custom CodeDom serializer for the UserControl. The
> custom CodeDom serializer derives from CodeDomSerializer class, which is in
> System.ComponentModel.Design.Serialization namespace. We need to override
> the Deserialize and Serialize methods in the custom CodeDom serializer
> class.
>
> Generally speaking, when we serialize a component, we use the base
> serializer for the component to do it. Unfortunately, the base serializers
> for both the DataGridViewColumnCollection and DataGridViewColumn instance
> could not serialize them at all. So we have to serialize them by ourselves.
>
> System.CodeDom namespace contains classes that can be used to represent the
> elements and structure of a source code document. CodeDOM is often used by
> designers to generate initialization code for component.
>
> The following is the code of the custom CodeDom serializer.
>
> public class MyCodeDomSerializer : CodeDomSerializer
> {
>
> public override object Deserialize(IDesignerSerializationManager
> manager, object codeObject)
> {
> CodeDomSerializer baseClassSerializer =
> (CodeDomSerializer)manager.GetSerializer(typeof(UserControl1).BaseType,
> typeof(CodeDomSerializer));
>
> return baseClassSerializer.Deserialize(manager, codeObject);
>
>
> }
>
> public override object Serialize(IDesignerSerializationManager
> manager, object value)
> {
> CodeDomSerializer baseClassSerializer =
> (CodeDomSerializer)manager.GetSerializer(typeof(UserControl1).BaseType,
> typeof(CodeDomSerializer));
> // serialize the UserControl
> object codeObject = baseClassSerializer.Serialize(manager,
> value);
>
> if (codeObject is CodeStatementCollection)
> {
> CodeStatementCollection statements =
> (CodeStatementCollection)codeObject;
>
> // The code statement collection is valid, so add a comment.
> string commentText = "This comment was added to this object
> by a custom serializer.";
> CodeCommentStatement comment = new
> CodeCommentStatement(commentText);
>
> statements.Insert(0, comment);
> // serialize the inner DataGridView's columns
>
> if (value is UserControl1)
> {
> DataGridViewColumnCollection innercolumns = (value as
> UserControl1).InnerDGVColumns;
> // declare the variable collection of columns in the
> inner DataGridView
> List<CodeVariableReferenceExpression> parameter_list =
> new List<CodeVariableReferenceExpression>();
> CodeArrayCreateExpression createArray = null;
> CodeMethodInvokeExpression methodcall = null;
>
> int i = 1;
>
> CodeStatementCollection col_Statements = null;
> foreach (DataGridViewColumn col in innercolumns)
> {
> /// serialize each column
> col_Statements = new CodeStatementCollection();
>
> CodeObjectCreateExpression col_ObjectCreate = new
> CodeObjectCreateExpression(col.GetType());
>
> CodeVariableDeclarationStatement
> col_VariableDeclaration = new
> CodeVariableDeclarationStatement(col.GetType(), "column" + i.ToString());
>
> CodeAssignStatement col_Assign_Create = new
> CodeAssignStatement(new CodeVariableReferenceExpression("column" +
> i.ToString()), col_ObjectCreate);
> // serialize the Width property of the column
> CodeAssignStatement col_Assign_width = new
> CodeAssignStatement(new CodeVariableReferenceExpression("column" +
> i.ToString() + ".Width"), new CodePrimitiveExpression(col.Width));
>
> CodeFieldReferenceExpression col_FieldReference =
> base.SerializeToExpression(manager, col) as CodeFieldReferenceExpression;
> if (col_FieldReference == null)
> {
> col_Statements.Add(col_VariableDeclaration);
> col_Statements.Add(col_Assign_Create);
> col_Statements.Add(col_Assign_width);
> parameter_list.Add(new
> CodeVariableReferenceExpression("column" + i.ToString()));
> }
>
> ///
>
> statements.AddRange(col_Statements);
> i++;
> }
>
> CodeFieldReferenceExpression target =
> base.SerializeToExpression(manager, value) as CodeFieldReferenceExpression;
> // if the designer hasn't all the columns to the inner
> DataGridView's column collection, add them by ourselves.
> if (target != null && parameter_list.Count > 0)
> {
> createArray = new
> CodeArrayCreateExpression(typeof(DataGridViewColumn),
> parameter_list.ToArray());
> methodcall = new CodeMethodInvokeExpression(new
> CodeVariableReferenceExpression(target.FieldName + ".InnerDGVColumns"),
> "AddRange", createArray);
>
> statements.Add(methodcall);
> }
> }
> }
> return codeObject;
> }
> }
>
> Adorn DesignerSerializerAttribute to the UserControl and
> DesignerSerializationVisibilityAttribute to the property for the inner
> DataGridView's columns.
>
> [DesignerSerializer(typeof(MyCodeDomSerializer),typeof(CodeDomSerializer))]
> public partial class UserControl1 : UserControl
> {
> public UserControl1()
> {
> InitializeComponent();
> }
>
> [Editor(typeof(MyCollectionEditor),typeof(UITypeEditor))]
>
> [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
> public DataGridViewColumnCollection InnerDGVColumns
> {
> get { return this.dataGridView1.Columns; }
> }
> }
>
> I also send you with this reply a sample project that contains both the
> custom UITypeEditor and CodeDom serializer. Please change the attachment's
> file extension .JPG to .ZIP and unzip it on your machine.
>
> Note: in the above sample code and the attached project, I only serialize
> the Width property of a DataGridView column just for an example. I'm sure
> you could serialize other proerties for the DataGridView column in the same
> way.
>
> Please try it and let me know if it is what you want.
>
>
> Sincerely,
> Linda Liu
> Microsoft Online Community Support