views:

214

answers:

2

When I construct my control (which inherits DataGrid), I add specific rows and columns. This works great at design time. Unfortunately, at runtime I add my rows and columns in the same constructor, but then the DataGrid is serialized (after the constructor runs) adding more rows and columns.

After serialization is complete, I need to clear everything and re-initialize the rows and columns. Is there a protected method that I can override to know when the control is done serializing?

Of course, I'd prefer to not have to do the work in the constructor, throw it away, and do it again after (potential) serialization. Is there a preferred event that is the equivalent of "set yourself up now", so that it is called once whether I'm serialized or not?


The serialization i speak of comes from the InitializeComponent() method in the form's code-behind file.

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
   ...
}

It would have been perfect if InitializeComponent was a virtual method defined by Control, then i could just override it and then perform my processing after i call base:

protected override void InitializeComponent()
{
    base.InitializeComponent();

    InitializeMe();
}

But it's not an ancestor method, it's declared only in the code-behind file.

i notice that InitializeComponent calls SuspendLayout and ResumeLayout on various Controls. i thought it could override ResumeLayout, and perform my initialization then:

public override void ResumeLayout()
{
   base.ResumeLayout();

   InitializeMe();
}

But ResumeLayout is not virtual, so that's out.

Anymore ideas? i can't be the first person to create a custom control.

+1  A: 

What seems to be happening is this:

  1. You've designed a custom DataGrid that adds its own rows and columns in the constructor
  2. You've added your custom DataGrid to a form
  3. You've found that the form designer has written code inside the form's InitializeComponent that adds those rows and columns a second time

The way the Windows Forms designer code generator works is that it looks at all of your object's properties, determines what the default values should be, and generates code for the properties that aren't set to the defaults. Unfortunately for you, the default state of a DataGrid is to have no rows and no columns.

You can alter this behaviour with a set of attributes, though. A straightforward way might be to add new copies of the Rows and Columns properties to your class, which just return base.Rows and base.Columns. Adding duplicate properties in this way lets you apply the DesignerSerializationVisibilty attribute to them, which you can use to force the forms designer to ignore the pre-populated rows and columns.

Tim Robinson
If you use DesignerSerializationVisibility to keep a property from being written to the .designer.cs, it's also a good idea to use [Browsable(false)] to prevent it from showing up in the Property Grid. If you're not planning to save it, it would be misleading to allow the user to edit it at design time.
Joe White
A: 

"Is there a protected method that I can override to know when the control is done serializing?"

No, not a protected method, but there is an interface. If your control implements ISupportInitialize, then when Visual Studio next saves the .designer.cs of a Form/UserControl that contains your custom control, it will automatically add a call to your BeginInit method immediately after your control is instantiated (but before any property values are assigned), and a call to EndInit after all properties are done being set.

However, while this gives you a lot of flexibility, it's kind of fiddly to get right for the kind of thing you describe (I've used it for much the same thing, so I know). If your descendant takes total control over the rows and columns, and it never makes sense for the user to edit them in the designer, then Tim's suggestion (DesignerSerializationVisibility) would be much simpler and easier to get right.

Joe White