Why should you make your lists observable?


NOTICE!!!!! This is preety much advanced feature to understand, but really, really basic feature to use. If you know how to use IList classes, all knowledge needed is already in your posession

So.. why?

For one reason. Old study showed that there is less than 3% of wrinting, all the rest is reading. But with using engine like data binding you lose reading quantity control. By my tests, writing accounts for less than 0.03%.

And since quantity of writing is so small, last thing wanted here is bogging down CPU with unprepared data. If you often sort or filter these actions become really expensive against rest of the software. Best approach is having prepared data which is accessible on the fly.

All sorting should be done on the fly as soon as item is added (yes, you also need to be aware you are not propagating any expensive events while doing that, as it will be shown in later chapter List providing widgets). And it all comes down to efficiency of your filter and sorting.

System.Data.Bindings applies sorting trough AVL sorting tree, with one really efficient difference. You never lose index access. Finding 345632th in 1 million of them. object is taking exactly the same time as finding Key. No more no less. It always gets to maximum of 20 iterations for 1 million elements. And having indexed access provides one to treat AVL sorting tree as IList instead of some list collection like all other solutions do.

Filtering on the other hand just takes reindexing of original list by only exposing valid items.

So, if you are well prepared and plan things you can do something like this example bellow (I personally don't use DataTable/DataView as I really don't find them neither usefull, nor efficient, but hey... everything is in the eye of the beholder):

... well for starters, I have this extension method. People who need/want to use DataTable/DataView should simply imagine any other data filling process.

public static IList ReadToList (this SqlCommand command);

this method reads directly into real objects instead of data rows (but more on this in description attributes which provide really functional descriptive access to classes)

which enables me to do this:

IList firstList = new ObservableSortListView (
new ObservableFilterListView (SomeSqlCommand.ReadToList(), filterDelegate),
sortDelegate, DuplicateHandling.CollectDuplicates);

or generic version of it

IList<MyObject> newList = new GenericObservableSortListView<MyObject> (
new GenericObservableFilterListView<MyObject> (SomeSqlCommand.ReadToList(), filterDelegate),
sortDelegate, DuplicateHandling.CollectDuplicates);

And I already get new sorted/filtered view, only filtered view and master view with one single command. Need another verion of sorted items? Simply... do this

IList secondList = new ObservableSortListView ((newList as IObservableListClient).ParentView,
someOtherSortDelegate, DuplicateHandling.Drop);

All wrapper lists here are implementing interface IObservableListClient, which is always providing you with reference to ParentView. And also takes ObservableSortListView as its base which only declares basic notifications by implementing INotifyPropertyChanged and IListEvents.

This is again much more efficient when writing, as you can control writing cache however you want. By signing up for modification events in original master list, cache can also track changes and store them back based on your request. Ok,... this is how I'm doing this. I never used DataAdaptor to get the same functionality as DataAdaptor provides it. But, at the same time I get full control over application data engine by using simple IList approach.

Need to be notified when count changes in your list? There is OnPropertyChanged. Need to know when items changed, there are IListEvents provided events.

But, since this more than sure still is not enough to persuade hardcore DataTable/DataView lover, I'm throwing DbObservableList on the table. DbObservableList is again wrapper only class, but it wrapps around DataTable or DataView and provides at the same time complete IList approach and access to wrapped object trough Table or DefaultView. And now you get everything compatible with before mentioned list view wrappers. This is simply accessed trough invoking something like this

IList myTableList = new DbObservableList (myTable);

DbObservableList simply makes event messaging in classic .Net objects more featurfull as I will now throw even better trick on the table. Since IListEvents avoids IBindingList flaw you can make hierarchical table... you can do something like this


public class MyNamedList : ObservableList
{
private string name = "";
public string Name {
get {return (name); }
set {
if (name.Equals(value))
return;
name = value;
OnPropertyChanged ("Name");
}
}

public MyNamedList (string aName, IList parent)
: base (parent)
{
name = aName
}
}

here we got simple ObservableArrayList which provides Name property. And lol, look at this (this is not really needed as you could simply derive such class extensions from previously mentioned views)

IList myBaseOfTheTree = new ObservableArrayList();
myBaseOfTheTree.Add (new MyNamedList ("Results of the first filter", firstList));
myBaseOfTheTree.Add (new MyNamedList ("Results of the second filter", secondList));
myBaseOfTheTree.Add (new MyNamedList ("Results of the Table", myTableList));

myBaseOfTheTree can now show whole hierarchy inside of any list based widget in Gtk.DataBindings (even ComboBox or DataEntry in its completition)

You just specify

myTreeView.ItemsDataSource = myBaseOfTheTree;
myTreeView.ColumnMappings = "{MyNamespace.MyObject} Name[Items name]; ... add any additional columns here"

and here it is. Perfect hierarchical TreeView. Always tracking changes in all lists needed in his model structure. Even if you would add or remove data to original lists or directly to the table, although ignoring changes which fall outside of specified filters. Change is reflected on the TreeView.

On the other hand... For those who are still naysayers... Gtk.DataBindings is more than happy to work with DataTable, DataView and DataRow.