views:

595

answers:

4

This is more of a design question.

I am building a tool that displays business objects in various ways (ie Tree Nodes, List View Items, Combo Boxes, Text Fields, etc). Anytime the user changes any of one of them, an event is raised that signals that that business object has been changed or the collection that it belongs to has been changed. Since this business object, or the collection that it might belong to, may be displayed in more than one place, each of those UI elements needs to be updated to reflect this change. Is there an elegant solution to having each type of UI element update correctly in the event of a change?

I have a few ideas of how this can be done, but I'd like to see if anyone has had this problem and was happy with their solution. This is a C# WinForm, but a solution can be in any language.

My current thoughts on the problem and a possible solution:

It gets more complicated when you want to clean up event bindings (ie businessObject.Changed -= ObjectChanged) when your business objects become part of a TreeNodeCollection/ListViewITemCollection/ComboBoxItemCollection and Clear() is called on the collection.

What about a "Service", where each object and its ui element can register itself with, where the business object's events can be listened for in one location, and each UI element would be updated when events are raised? When all UI elements have unregistered themselves, then the subscription to that object's event is removed.

The problem with this solution is that every control will have to be responsible for registering the UI component and the object on every creation - which can get messy.

Your thoughts?

+2  A: 

Use a messaging system. Create a delegate like this:

public delegate void ObjectRefresh(BusinessObject obj);

Then, in your BusinessObject class:

public event ObjectRefresh;

And when a property is changed:

if (ObjectRefresh)
    ObjectRefresh(this);

And on all of your uis:

BusinessObject obj = GetBusinessObject();
obj.ObjectRefresh += this.ObjectRefresh;
...
private void ObjectRefresh(BusinessObject obj)
{
    // update UI
}

:)

nlaq
I'd suggest putting the code to call the delegate in its own (protected) method, OnObjectRefresh.
Chris Charabaruk
+3  A: 

You may want to try the observer pattern. http://en.wikipedia.org/wiki/Observer_pattern

boxoft
And extending further to MVC or MVP patterns.
icelava
This is the best explanation I've seen, and examples in a multitude of languages too.
Jeremy
A: 

Have a look at Bindable Linq ... a solution to this problem by Paul Stovell.

http://www.codeplex.com/bindablelinq

If it doesn't provide a solution to your problem it would give you some insite into writing this yourself.

Have a read through his blog as well.

http://www.paulstovell.com/blog/

JTew
A: 

make sure you really need this, i.e. that it isn't happening already. For example, if your GUI objects are bound to datasets and your business objects merge changes into dataset, the dataset will automatically notify the gui objects that the data has changed; a database gui object will update itself automatically

if not, then the Observer pattern as mentioned above is what you want

Steven A. Lowe