> OK, so it's a known problem. We had our own implementation of
> IBindingList before switching to BindingList<T>, but as you
> say the event notification is tricky to get right.

        The notification isn't that hard. Actually it's a 1 minute job. It's 
the state of the average control you can buy (including
the datagridview and datagrid controls shipped by MS, these also have problems) 
which is much harder to deal with.

> Is there any good in-depth documentation of how the data
> binding protocol is supposed to work, especially using
> DataGrid and DataGridView? Sometimes in the MSDN
> documentation it feels like "DataSet supports data binding.
> If you have custom collection and classes here are the
> interfaces we use... good luck...".

        In general, databinding doesn't work. This is because there's no hard 
standard defined. For example, for property discovery
by grids they should use ITypedList, as that's the least intrusive way to do it 
and it doesn't create dummy instances which can
trigger BL code to activate etc. etc. (or lazy loading :)). Some grids, let's 
not name names here, don't use ITypedList, and
therefore trigger all kinds of code.

        Similar stuff with IBindingList. You can bind an arraylist to a grid 
just fine. The problems begin when the arraylist is
actually a custom collection with own events which are triggered by changes 
occuring in the objects IN the collection. You then can
run into a strange loop of events, where changes in the collection trigger 
re-render code of the grid, but that won't always work as
the grid isn't done yet with the change which triggered the redraw... <insert 
nightmare description here>

        Microsoft's documentation has a tendency of explaining even the most 
stupidist silly things an average joe will run into,
but when framework developers (you know, the people who write a framework with 
.net) need documentation, it's hardly there (or
stating the obvious. "Gee, the property Handler returns a handler")

        In general, a grid checks for the columns to render the ITypedList 
implementation and acts accordingly. This is different in
.NET 2.0 as it seems, where dummy instances are added all over the place. I'm 
not exxagerating when I say that Microsoft didn't do a
good job by explaining and designing this.

        For the data management, thus what to do when the bound collection 
changes, IBindingList is used. You should simply raise
ListChanged when you add, insert, remove or move an object in the list. The 
grid will then take care of the rest. This is what
BindingList does for you. AddNew() is used for the new row in the grid and is 
only called if AllowNew is returning true. A new
instance added by AddNew() is special, as someone already mentioned. The reason 
is that if someone presses ESC, the instance added
by AddNew should be destroyed. So it's not really added at first, until the new 
row is actually accepted. You know this best by
implementing IEditableObject on the objects in the collection.

> But then again adding 10000 objects is not something you
> would do when working in a grid so maybe we are trying add
> too much responsibility to a single typed collection class...
> what's you strategies for custom business object collections?

        Adding 10000 objects to a custom collection shouldn't be a problem, the 
thing is that what do you want to do with those
objects? No user can handle 10000 objects on a screen, so it's a bit useless to 
show them in a grid, a user is better helped with a
view on the 10000 objects based on a filter for example. In which case you have 
to implement IListSource which returns the actual
binding object to the grid and on which you implement ITypedList and 
IBindingList on.

        Yes, lots of fun ;)

                Frans
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------

>
> // Kristofer
>
> -----Original Message-----
> From: Discussion of advanced .NET topics.
> [mailto:[EMAIL PROTECTED] On Behalf Of
> gregory young
> Sent: den 31 oktober 2006 17:07
> To: ADVANCED-DOTNET@DISCUSS.DEVELOP.COM
> Subject: Re: [ADVANCED-DOTNET] BindingList<T>.AddNew
> performance problem
>
> What we did to work around this was implement IBindingList on
> our own using a hashlist .. you could also fairly easily
> override the behavior to index your list in a derived class
> by overriding add/remove/etc (note that if you go this route
> you will need to get out reflector to make sure you raise the
> proper events etc and its a bad overall design).
>
> Cheers,
>
> Greg
>
> On 10/31/06, Krebs Kristofer <[EMAIL PROTECTED]> wrote:
> > Hi!
> >
> > I found a weird thing while I was investigating a performance issue.
> We
> > use BindningList<T> as base class for our business object
> collections.
> > It seems that BindingList<T>.AddNew calls IndexOf(T item) (which has
> to
> > iterate and do Equals for all items in the collection to find it...
> it's
> > probably last) after the call to AddNewCore IF the item (of T)
> overrides
> > Equals or implements IEquatable<T>. This makes adding new items this
> way
> > go slower and slower. Adding object via the usual Add does
> not cause
> > this problem.
> >
> > So, my question is why, and how can I avoid this behaviour? I any
> case;
> > beware of this...
> >
> > Test code ("dry coded"):
> >
> > TestEntityCollection coll = new TestEntityCollection();
> >
> > // Takes forever on my machine i.e. at least 25 seconds....
> > for (int i = 0; i < 10000; i++) {
> >    TestEntity obj = coll.AddNew();
> >    obj.Name = "Name" + i;
> > }
> >
> > // This is much faster, < 0.5 seconds
> > for (int i = 0; i < 10000; i++) {
> >    TestEntity obj = new TestEntity();
> >    obj.ID = Guid.NewGuid();
> >    obj.Name = "Name" + i;
> >    coll.Add(obj);
> > }
> > ....
> >
> > public class TestEntity : IEquatable<TestEntity> {
> >     private Guid _id;
> >     private string _name;
> >
> >
> >     public Guid ID { get { return _id; } set { _id = value; } }
> >     public string Name { get { return _name; } set { _name
> = value; }
> >
> >
> >     // This causes bad performance on AddNew it seems, remove
> > IEquatable
> >     // implementation to see the difference. Overriding
> Equals(object)
> >     // causes the same thing
> >     public bool Equals(TestEntity other) {
> >         return ((object)other != null && this.ID.Equals(other.ID);
> >     }
> > }
> >
> > public class TestEntityCollection : BindingList<TestEntity>
> > {
> >   public override object AddNewCore() {
> >      TestEntity item = new TestEntity();
> >      item.ID = Guid.NewGuid();  // Just an example of id
> initialization
> >      Add(item);
> >      return item;
> >   }
> > }
> >
> > ===================================
> > This list is hosted by DevelopMentor(r)  http://www.develop.com
> >
> > View archives and manage your subscription(s) at
> http://discuss.develop.com
> >
>
>
> --
> If knowledge can create problems, it is not through ignorance that we
> can solve them.
>
> Isaac Asimov
>
> ===================================
> This list is hosted by DevelopMentor(r)  http://www.develop.com
>
> View archives and manage your subscription(s) at
> http://discuss.develop.com
>
> ===================================
> This list is hosted by DevelopMentor.  http://www.develop.com
>
> View archives and manage your subscription(s) at
> http://discuss.develop.com
>
>

===================================
This list is hosted by DevelopMentorĀ®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to