IBindingList design flaw and lack of functionality
1) Design flaw
Ok, first focus of this is based on the flaw. IBindingList provides its
notifications trough ListChanged event. And this event is really
flawed. I will simply focus directly to the place where flaw exists.
public delegate void ListChangedEventHandler (
object sender, ListChangedEventArgs e)
ListChangedEventArgs
ListChangedType ListChangedType
int NewIndex
int OldIndex
PropertyDescriptor PropertyDescriptor
Ok, so what is wrong with this picture? Well, ListChangedType.ItemDeleted is completely flawed and is usable only in corner cases. Why?
Event is always sent after item is deleted and item doesn't exist
anymore in that list, so if one keeps cache in Hashtable or different
hierarchy, he can't know what to remove. Keeping two lists and rely on
IBindingList is also impossible. Which makes it only usable in corner
cases which are directly involved to avoid the problem this event
creates.
Ok, me saying "Event is always sent after item is deleted" isn't
correct either. IBindingList is interface not class. Which now really
means there is no way of knowing if deletition has already happened.
This is simply defaulted to "you need to know handling of every single
IBindingList provider if you wanna be sure what just happened"
Funny thing is that they still provide index with this but this one now points to either invalid or incorrect location.
2) Lack of functionality
Typical DataGrid in .Net is linear. Msking TreeView as dumb as this
would be one of the easiest things on this world. But considering great
work developers put into Gtk TreeView I felt kinda sad not to use that
power. Gtk TreeView provides hierarchy and as such I also wanted to be
implemented. By using complete raw power of TreeView.
Now... as soon as you start talking hierarchy... how can you provide hierarchical description with int? IBindingList only has
int NewIndex and int OldIndex. Which puts everything into question.
1) Searching manually for index?
2) Provide something which better suits this functionality
This is why IListEvents always provides int[] as index instead of int.
As I said in the start, providing linear only capability would be
easiest, but I really wanted to go step forward and be able to do this
for example.
public class MyList : ObservableArrayList
{
private string name = "unnamed";
public string Name {
get { return (name); }
set {
if (name == value)
return;
name = value;
OnPropertyChanged ("Name");
}
}
public MyList (string aName)
{
name = aName;
}
}
public class MyObject : BaseNotifyPropertyChanged
{
private string name = "unnamed";
public string Name {
get { return (name); }
set {
if (name == value)
return;
name = value;
OnPropertyChanged ("Name");
}
}
private string lastname = "unnamed";
public string LastName {
get { return (lastname); }
set {
if (lastname == value)
return;
lastname = value;
OnPropertyChanged ("LastName");
}
}
public MyObject (string aName, string aLastName)
{
name = aName;
}
}
....
And then do something like this:
MyList list = new MyList ("base");
list.Add (new MyList ("List A"));
list.Add (new MyList ("List B"));
(list[0] as MyList).Add (new MyObject ("Object with name A", "A"));
(list[1] as MyList).Add (new MyList ("List BA"));
((list[1] as MyList)[0] as MyList).Add (new MyObject ("Object with name B", "B"));
Assign this to TreeView with mapping
myTreeView.ItemsDataSource = list;
myTreeView.ColumnMappings = "{MyNamespace.MyObject} Name[Items name]<<; LastName[Items last name]";
which produces this final TreeView result:
Items name
|
Items last name
|
List A
|
|
Object with name A
|
A
|
List B
|
|
List BA
|
|
Object with name B
|
B
|
Except there is one really nice sugar. No mater where in code you add,
change, delete items TreeView effect is instant as long as
ItemsDataSource is specified. Items are always hierarchically in sync
with original list. Data binding even avoids properties which do not
exist in that specific class and shows only existing.