I am having trouble understanding the databinding in my Eclipse RCP application. I just can't figure out how it's supposed to work..
Here's what I want to do
I have a View where a list of texts should be displayed. The texts are "stored" in a simple List<String>
which is provided via a singleton (for demonstration purpose only ;)). So whoever uses the ListProvider
will get the list of texts. When the list changes I want my View to automatically update the table contents.
Here's what I've done so far
My List provider is an Observable
that will notify observers when the list changes.
In my view I create an Observer to watch the list provider and when the observer is notified I refresh my view.
Code for the ListProvider
:
public class ListProvider extends Observable {
private Stack<String> hist;
private static ListProvider instance;
// Singleton implementation
public static ListProvidergetInstance() {
if (null == instance) {
instance = new ListProvider
}
return instance;
}
public void add(String text) {
if (this.hist.size() == MAX_SIZE) {
this.hist.remove(MAX_SIZE-1);
}
this.hist.add(0, text);
// notify all observers
this.setChanged();
this.notifyObservers();
}
}
Code for the view:
public class TestView extends ViewPart {
private TableViewer viewer;
[...]
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return ClipboardHistory.getInstance().getList().toArray();
}
}
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
IContentProvider contentProvider = new ViewContentProvider();
viewer.setContentProvider(contentProvider);
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setInput(getViewSite());
Observer listObserver = new Observer() {
@Override
public void update(Observable o, Object arg) {
// update the table viewer
viewer.refresh();
}
};
ListProvider.getInstance().addObserver(listObserver);
}
}
Question
Is using Observer
and Observable
the "right" way to go or am I missing something? I am not sure I've grasped the concept of RCP Databinding...
I recommend you reading JFace Databinding and make use of ViewerSupport
, ObservableListContentProvider
and BeanProperties
to simplfy the job.
You can also see a working example JFace Databinding Snippet: Model to TableViewer binding for a reference, where the binding is done at last with the help of ViewerSupport
:
(...)
TableViewer peopleViewer = new TableViewer(committers);
ViewerSupport.bind(peopleViewer, new WritableList(viewModel.getPeople(),
Person.class), BeanProperties.value(Person.class, "name"));
With those helpers you won't need to implement the Observer
for your list, and if you want your viewer to update its labels when data is modified take a look in the same example to PropertyChangeSupport
, which allows you to refresh the viewer on every change on any element of the list that you notify through it. It's important that you use BeanProperties
for the binding.
I don't think there's anything wrong with your approach with one possible exception. You need to make sure that the viewer is refreshed in the UI thread:
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
viewer.refresh();
}
});
However there are things that you can do to make the table update more efficient. In your code above it appears to only add a single item at the top of the table, so you'd be better with a call to:
viewer.insert( text, 0 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With