Difference between revisions of "JFace Data Binding/Tutorial"

From Eclipsepedia

Jump to: navigation, search
(Data Binding Tutorial)
(Data Binding Tutorial)
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
== Data Binding Tutorial ==
 
== Data Binding Tutorial ==
 
--[[User:Frank.schaare.gmail.com|Frank.schaare.gmail.com]] 20:24, 12 October 2007 (EDT)
 
--[[User:Frank.schaare.gmail.com|Frank.schaare.gmail.com]] 20:24, 12 October 2007 (EDT)
 +
 +
This tutorial is not yet updated to use the new Properties API which is as of Eclipse 3.5 the recommended way of using databinding. For a tutorial which uses the Properties API please see [http://www.vogella.com/articles/EclipseDataBinding/article.html Eclipse JFace Databinding and Validation - Tutorial]
 
=== Terms ===
 
=== Terms ===
 
----
 
----
Line 12: Line 14:
 
<pre>
 
<pre>
 
public void createPartControl(Composite parent){
 
public void createPartControl(Composite parent){
 
+
                name = new Text(parent, SWT.BORDER);
name = new Text(parent, SWT.BORDER);
+
        final GridData gd_name = new GridData(SWT.FILL, SWT.CENTER, true, false);
final GridData gd_name = new GridData(SWT.FILL, SWT.CENTER, true, false);
+
        name.setLayoutData(gd_name);
name.setLayoutData(gd_name);
+
 
+
 
}
 
}
 
</pre>
 
</pre>
 
<p>That Text name represents the Target of our binding. Let's add a simple Model:</p>
 
<p>That Text name represents the Target of our binding. Let's add a simple Model:</p>
 
<pre>
 
<pre>
static class Person extends ModelObject{
+
static class Person extends ModelObject
 +
        {
 
// A property...
 
// A property...
 
String name = "HelloWorld";
 
String name = "HelloWorld";
Line 34: Line 35:
 
}
 
}
 
</pre>
 
</pre>
<p>As you may have noticed, the Person Class extends '''Model Object'''. If you want to bind your Domain Models, you'll have to ensure support for PropertyChangeSupport. The easiest way to achieve this, is to extend Model Object. You'll find a suitable Template in org.eclipse.jface.examples.databinding package.</p>
+
<p>As you may have noticed, the Person class extends '''ModelObject'''. If you want to bind your domain models, you'll have to ensure support for PropertyChangeSupport. The easiest way to achieve this, is to extend Model Object. You'll find a suitable Template in org.eclipse.jface.examples.databinding package.</p>
 
<p>To create your first binding, you need to instantiate a '''DataBindingContext'''. Create a method like this:</p>
 
<p>To create your first binding, you need to instantiate a '''DataBindingContext'''. Create a method like this:</p>
 
<pre>
 
<pre>
 
private DataBindingContext initDataBindings() {
 
private DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
+
        DataBindingContext bindingContext = new DataBindingContext();
  
return bindingContext;
+
        return bindingContext;
 
}
 
}
 
</pre>
 
</pre>
Line 46: Line 47:
 
<pre>
 
<pre>
 
private DataBindingContext initDataBindings() {
 
private DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
+
        DataBindingContext bindingContext = new DataBindingContext();
  
        IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
+
                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
  
return bindingContext;
+
        return bindingContext;
 
}
 
}
 
</pre>
 
</pre>
Line 62: Line 63:
 
<pre>
 
<pre>
 
private DataBindingContext initDataBindings() {
 
private DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
+
        DataBindingContext bindingContext = new DataBindingContext();
        IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
+
  
IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");
+
                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
 +
        IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");
  
return bindingContext;
+
        return bindingContext;
 
}
 
}
 
</pre>
 
</pre>
Line 79: Line 80:
 
<pre>
 
<pre>
 
private DataBindingContext initDataBindings() {
 
private DataBindingContext initDataBindings() {
DataBindingContext bindingContext = new DataBindingContext();
+
        DataBindingContext bindingContext = new DataBindingContext();
        IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
+
IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");
+
  
bindingContext.bindValue(nameTextObserveWidget, personNameObserveValue, null, null);
+
                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
 +
        IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");
  
return bindingContext;
+
        bindingContext.bindValue(nameTextObserveWidget, personNameObserveValue, null, null);
 +
 
 +
        return bindingContext;
 
}
 
}
 
</pre>
 
</pre>
Line 97: Line 99:
 
</p>
 
</p>
 
<p>That's it. You successfully created your first JFace Data Binding !</p>
 
<p>That's it. You successfully created your first JFace Data Binding !</p>
 +
 
=== Introducing UpdateValueStrategy ===
 
=== Introducing UpdateValueStrategy ===
 
----
 
----
Line 111: Line 114:
 
<p>As another nested inner Class, you'll find Class '''FirstWizardPage'''. In createControl method, a DataBindingContext is instantiated at first, no news right here. The binding is created with this code:</p>
 
<p>As another nested inner Class, you'll find Class '''FirstWizardPage'''. In createControl method, a DataBindingContext is instantiated at first, no news right here. The binding is created with this code:</p>
 
<pre>
 
<pre>
dbc.bindValue(SWTObservables.observeText(text, SWT.Modify),
+
dbc.bindValue(
 +
                SWTObservables.observeText(text, SWT.Modify),
 
((SampleWizard) getWizard()).getModel().intValue,
 
((SampleWizard) getWizard()).getModel().intValue,
 
new UpdateValueStrategy().setAfterConvertValidator(new SingleDigitValidator()),
 
new UpdateValueStrategy().setAfterConvertValidator(new SingleDigitValidator()),
null);
+
null
 +
        );
 
</pre>
 
</pre>
 
<p>Oooh, what a monster. Fortunately, you have already some good knowledge to understand whats going on here. The first parameter is a Target IObservableValue bound to the Wizards Text control. It's provided with a SWT.Modify event, which means that anytime, the controls text changes, the Data Binding mechanism is invoked. The second parameter is the already dicussed WritableValue. Remember, it's an IObservableValue implementation, so again, we deal with two Observables. The third parameter ist the most interessting and new part of the story: first, a new '''UpdateValueStrategy''' is instantiated. This is required, when you have to deal with:
 
<p>Oooh, what a monster. Fortunately, you have already some good knowledge to understand whats going on here. The first parameter is a Target IObservableValue bound to the Wizards Text control. It's provided with a SWT.Modify event, which means that anytime, the controls text changes, the Data Binding mechanism is invoked. The second parameter is the already dicussed WritableValue. Remember, it's an IObservableValue implementation, so again, we deal with two Observables. The third parameter ist the most interessting and new part of the story: first, a new '''UpdateValueStrategy''' is instantiated. This is required, when you have to deal with:
Line 132: Line 137:
 
<li>Value set</li>
 
<li>Value set</li>
 
</ul>
 
</ul>
You may have a look to the '''UpdateValueStrategy''' JavaDocs, which is quite voluptuous documentated, for further Information.
+
You may have a look to the '''UpdateValueStrategy''' JavaDocs, which are quite voluminously documented, for further information.
 
<p>In our case, the method setAfterConvertValidator(IValidator validator) is called, which invokes the validator after the source value is converted to the type of the destination observable. setAfterConvertValidator eats an IValidator as param. This one is offered as another inner Class nested in Class FirstWizardPage. It simply checks, whether incoming value is between 0 and 9. If not, a '''ValidationStatus(IStatus.ERROR, message)''' is returned, resulting WizardPage1 moaning about the wrong value:</p>
 
<p>In our case, the method setAfterConvertValidator(IValidator validator) is called, which invokes the validator after the source value is converted to the type of the destination observable. setAfterConvertValidator eats an IValidator as param. This one is offered as another inner Class nested in Class FirstWizardPage. It simply checks, whether incoming value is between 0 and 9. If not, a '''ValidationStatus(IStatus.ERROR, message)''' is returned, resulting WizardPage1 moaning about the wrong value:</p>
 
[[Image:Snippet014WizardDialog.JPG]]
 
[[Image:Snippet014WizardDialog.JPG]]
=== Binding Collections ===
 
----
 
 
=== ObservablesManager ===
 
 
----
 

Latest revision as of 12:59, 10 May 2012

Contents

[edit] Data Binding Tutorial

--Frank.schaare.gmail.com 20:24, 12 October 2007 (EDT)

This tutorial is not yet updated to use the new Properties API which is as of Eclipse 3.5 the recommended way of using databinding. For a tutorial which uses the Properties API please see Eclipse JFace Databinding and Validation - Tutorial

[edit] Terms


  • Model: a Model represents the Domain Model of your Application.
  • Target: a Target represents the GUI side.

[edit] A first simple binding


Looking at the example snippets, you'll see a few SWT examples. This time, we'll create a very simple RCP view. Our createPartControl method has just one Text Element:

	public void createPartControl(Composite parent){
                name = new Text(parent, SWT.BORDER);
	        final GridData gd_name = new GridData(SWT.FILL, SWT.CENTER, true, false);
	        name.setLayoutData(gd_name);
	}

That Text name represents the Target of our binding. Let's add a simple Model:

	static class Person extends ModelObject
        {
		// A property...
		String name = "HelloWorld";

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}
	}

As you may have noticed, the Person class extends ModelObject. If you want to bind your domain models, you'll have to ensure support for PropertyChangeSupport. The easiest way to achieve this, is to extend Model Object. You'll find a suitable Template in org.eclipse.jface.examples.databinding package.

To create your first binding, you need to instantiate a DataBindingContext. Create a method like this:

	private DataBindingContext initDataBindings() {
	        DataBindingContext bindingContext = new DataBindingContext();

	        return bindingContext;
	}

Next, we add a IObservableValue Object for the Target:

	private DataBindingContext initDataBindings() {
	        DataBindingContext bindingContext = new DataBindingContext();

                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);

	        return bindingContext;
	}

The observeText method takes two params

  • name: the observed Control
  • event: when the model will be updated. Choices are SWT.FocusOut, SWT.Modify or SWT.NONE

Second, we add a IObservableValue Object for the Model:

	private DataBindingContext initDataBindings() {
	        DataBindingContext bindingContext = new DataBindingContext();

                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
	        IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");

	        return bindingContext;
	}

The observeValue method takes two params

  • bean: the observed bean
  • propertyName: the name of the observed property, in our case the persons name.

Last, we need to bind Target and Model. This is done through the DataBindingContext#bindValue method:

	private DataBindingContext initDataBindings() {
	        DataBindingContext bindingContext = new DataBindingContext();

                IObservableValue nameTextObserveWidget = SWTObservables.observeText(name, SWT.FocusOut);
	        IObservableValue personNameObserveValue = BeansObservables.observeValue(person, "name");

	        bindingContext.bindValue(nameTextObserveWidget, personNameObserveValue, null, null);

	        return bindingContext;
	}

The bindValue method takes four params

  • targetObservableValue: our first created IObservableValue
  • modelObservableValue: our second created IObservableValue
  • UpdateValueStrategy targetToModel: will be dicusssed later
  • UpdateValueStrategy modelToTarget: will be dicusssed later

That's it. You successfully created your first JFace Data Binding !

[edit] Introducing UpdateValueStrategy


Next, we'll take a closer look at Snippet014WizardDialog, to explore some advanced features.

Snippet014WizardDialog includes an inner class SampleWizardModel:

	static class SampleWizardModel {
		IObservableValue intValue = new WritableValue(null, Integer.class);
		IObservableValue dateValue = new WritableValue(null, Date.class);
	}

Again, you'll find an IObservableValue, but with a few differences to our first example. First, it is instantiated as a WritableValue(Object initialValue, Object valueType). This is a mutable implementation of IObservableValue that will maintain a value and fire change events when the value changes. Second, the IObservableValue is instantiated inside the Model, differently from our first example. If you are in a situation where you can't get PropertyChangeSupport by extending a class similar to ModelObject, this variant may be a good alternative.

As another nested inner Class, you'll find Class FirstWizardPage. In createControl method, a DataBindingContext is instantiated at first, no news right here. The binding is created with this code:

	dbc.bindValue(
                SWTObservables.observeText(text, SWT.Modify),
		((SampleWizard) getWizard()).getModel().intValue,
		new UpdateValueStrategy().setAfterConvertValidator(new SingleDigitValidator()),
		null
        );

Oooh, what a monster. Fortunately, you have already some good knowledge to understand whats going on here. The first parameter is a Target IObservableValue bound to the Wizards Text control. It's provided with a SWT.Modify event, which means that anytime, the controls text changes, the Data Binding mechanism is invoked. The second parameter is the already dicussed WritableValue. Remember, it's an IObservableValue implementation, so again, we deal with two Observables. The third parameter ist the most interessting and new part of the story: first, a new UpdateValueStrategy is instantiated. This is required, when you have to deal with:

  • Validation
  • Conversion
  • Automatic processing

in your binding.

It offers five phases for manipulation where you can hook on:

  • Validate after get
  • Conversion
  • Validate after conversion
  • Validate before set
  • Value set

You may have a look to the UpdateValueStrategy JavaDocs, which are quite voluminously documented, for further information.

In our case, the method setAfterConvertValidator(IValidator validator) is called, which invokes the validator after the source value is converted to the type of the destination observable. setAfterConvertValidator eats an IValidator as param. This one is offered as another inner Class nested in Class FirstWizardPage. It simply checks, whether incoming value is between 0 and 9. If not, a ValidationStatus(IStatus.ERROR, message) is returned, resulting WizardPage1 moaning about the wrong value:

Snippet014WizardDialog.JPG