Got more questions? Find advice on: SQL | XML | Regular Expressions | Windows
in Search
Welcome to AspAdvice Sign in | Join | Help

Justin Lovell's Blog

Mood: The Grumpy Coder

Collection management during design-time

This has become a FAQ over the time and so I have decided to just write a darn blog post about it.

With collection management during design-time is fairly easy. In fact, too easy. However, sooner or later, you would like to have a multi-dimension collection. Let's take for example:

[ParseChildren(true, "Tabs")]
[PersistChildren(false)]
public abstract class Menu : Control {
   private MenuItemCollection _MenuItems = new MenuItemCollection();

   [NotifyParentProperty(true)]
   [PersistenceMode(PersistenceMode.InnerProperty) ]
   [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
   public MenuItemCollection MenuItems {
      get {
        return this._MenuItems;
      }
   }
}

public class MenuItemCollection : CollectionBase {
   public new MenuItem this[int index] {
      get {
         return (MenuItem)base.this[index];
      }
   }
}

public class MenuItem : Menu {
   // ...
}

public class MainMenu : Menu {
   // ...
}

One common trait that will build up is the MainMenu control will have the Menu property which will open up a designer to add MenuItem instances. No big deal! However, your menu items also has the Menu property which will open up another designer. So you can add menu items within an menu item. You think that you are finished so you accept the changes and close the designer only to be met with an error message “object reference is not set to an instance object”.

The cause of the problem is very vague. However, let me tell you a little secret -- the problem is not with your code; it is with Microsoft's. Luckily, you can override their designer for the collection management and just put enough effort into the designer to make that pesky error message go away. So, here is the code for the new, overridden designer:

public class MenuItemCollectionEditor : CollectionEditor {
   private CollectionForm collectionForm;

   public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
      if ((collectionForm != null) && (collectionForm.Visible)) {
         MenuItemCollectionEditor editor = new MenuItemCollectionEditor(CollectionType);
         return editor.EditValue(context, provider, value);
      }
      else
         return base.EditValue(context, provider, value);
   }

   protected override CollectionEditor.CollectionForm CreateCollectionForm() {
      collectionForm = base.CreateCollectionForm();
      return collectionForm;
   }

   public MenuItemCollectionEditor(Type type) : base(type) {
   }
}

If you had to look carefully at the code, you will eventually find out that the cause of error message was because only one designer instance can be “open” at any given time. The above code just rectifies that so that it creates multiple instances of the designers.

To use the above code, just pop the following attribute on the collection:

[Editor(typeof(MenuItemCollectionEditor), typeof(UITypeEditor))]
public class MenuItemCollection : CollectionBase {
   // ...
}

Sponsor
Published Tuesday, September 07, 2004 10:02 AM by jlovell

Comments

 

jlovell said:

Interesting...
September 7, 2004 3:25 PM
 

jlovell said:

I may need to give this a better look through once your sql thing is done running. It sounds right, but at the same time, it doesn't. I've used intense collections before, and never ran into that error. :-\

Anyways, you're not going to like the results buddy. :( it's taking a heavy hit with 5 concurrent users looping.

it's predominantly:
937500 ticks to execute for 1000 rows with one user.
2500000 ticks to execute for 1000 rows with two users.
3750000 ticks to execute for 1000 rows with three users.

... sorry to say, but it just adds up along the way.

100 concurrent users may destroy your reputation. It might be better to reconsider the outcome. I used Customers table in the northwind database with 800k records, and added a where clause in your cursor declaration. It's in a procedure that's called in a loop, and the ticks count starts and ends right before and right after the ExecuteReader() respectively.

I'm emailing you the logs now.
September 8, 2004 3:31 AM
Anonymous comments are disabled