Search code examples
c#winformsuser-interfacedata-bindinglistview

How should data be synchronized between a WinForms GUI control and the client class?


What method is considered the "standard" for keeping data structures within GUI controls synchronized with the data structures that are maintained by the application?

For example: In WinForms, if one creates a ListView instance, rather than pointing it to a data structure that represents the items to appear within the list, one must programmatically instantiate ListViewItem(s) and call an .Add method to manually replicate them, one by one, into a data structure that is internal to the ListView itself. This makes sense from a threading standpoint, and it also makes sense within the context of rendering that a control should require a specialized data structure to exist for which the control alone knows the details regarding maintenance.

However, this creates two issues:

Redundancy: If the client class manages its own list of entities, to allow the user to select among them from the WinForms UI, this entire list must be read, converted and then recreated inside of the UI control via methods such as: .Add(ListViewItem item) Lists now occupy twice as much memory.

Complexity: Since two lists now exist, one must programmatically ensure that they remain synchronized. This can be achieved with events that are fired from the client class's collection object, or a programmer can simply be careful to always add/remove from one list when they add/remove from the other.

I have seen many instances where programmers will take the shortcut of using a UI element like a ListView as the actual collection object used to maintain the list. For example, each user entered item will be immediately inserted into the ListView, and then when it comes time to access to user's entires, the application just iterates through the ListView. This method fails to apply when you are properly seperating business/application logic from UI logic.

Overall, something just doesn't seem right about storing application data within a data structure that is internal to a GUI control. Likewise, storing two lists and keeping them programmitically synchronized doesn't seem like an elegant solution either. Ideally, one would need only to supply a UI element with a reference to a list that resides within the scope of the client.

So, what is the "right" way to approach this problem?


Solution

  • Every UI control needs some state of its own. With complex controls (like ListView) that state is correspondingly complex. The trick is to make the maintenance of the controls state as simple as possible. With a standard ListView, that's not possible -- the programmer has to do the work.

    That's one reason I wrote ObjectListView (an open source wrapper around .NET WinForms ListView). It allows you to use a ListView at a higher level where the maintenance of the controls state is invisible. An ObjectListView operates on your model objects directly:

    this.objectListView1.Objects = listOfModelObjects;
    this.objectListView1.SelectedObject = aPerson;
    

    Once you can work at this level, data binding itself is no so useful. But, if you really want to use it, you can use the data-bindable DataListView from the ObjectListView project. It gives you the best of both worlds.

    With an ObjectListView, there is no reason to switch to the far less interesting DataGridView. An ObjectListView gives you the ease of DataGridView with the nice UI features of a ListView, then plus some more:

    alt text