Die Klasse org.jowidgets.util.binding.Bind
kann verwendet werden, um zwei Observable Values aneinander zu
binden binden. Sie hat die folgenden statischen Methoden:
public static <VALUE_TYPE> IBinding bind(
final IObservableValue<VALUE_TYPE> source,
final IObservableValue<VALUE_TYPE> destination) {...}
public static <SOURCE_TYPE, DESTINATION_TYPE> IBinding bind(
final IObservableValue<SOURCE_TYPE> source,
final IObservableValue<DESTINATION_TYPE> destination,
final IBindingConverter<SOURCE_TYPE, DESTINATION_TYPE> converter) {...}
Die erste Methode kann verwendet werden, um typgleiche Values
aneinander zu binden, die zweite Methode erlaubt das Binden von
unterschiedlichen Typen. Die Bindung ist
immer bidirektional, das
bedeutet, Änderungen auf source ändern die
destination und Änderungen auf
destination ändern die
source. Haben source und
destination initial einen unterschiedlichen
Wert, nimmt durch das Binden destination den
Wert von source an. Beide Methoden liefern
eine IBinding Referenz zurück. Diese hat die
folgenden Methoden:
void setBindingState(boolean bind);
void unbind();
void bind();
boolean isBound();
void dispose();
boolean isDisposed();
Die ersten drei Methoden dienen zum Setzen, die vierte zum
Auslesen des binding State. Dadurch kann das
Binding temporär gelöst und später wieder aktiviert werden.
Initial ist der binding State
true. Durch den Aufruf von
dispose() wird das Binding dauerhaft gelöst,
und die internen Referenzen auf source und
destination verworfen. Nach einem Aufruf von
dispose() kann nur noch die Methode
isDisposed() aufgerufen werden. Alle anderen
Methodenaufrufe führen dann zu einer
IllegalStateException.
Um Obervable Values unterschiedlichen Typs zu binden, kann ein
IBindingConverter verwendet werden. Dieser
ist wie folgt definiert:
1 public interface IBindingConverter<SOURCE_TYPE, DESTINATION_TYPE> {
2
3 DESTINATION_TYPE convertSource(SOURCE_TYPE sourceValue);
4
5 SOURCE_TYPE convertDestination(DESTINATION_TYPE destinationValue);
6 }Das folgende Beispiel implementiert einen Binding Converter, welcher eine Liste in ein Array und zurück konvertiert:
1 public final class ListArrayBindingConverter implements IBindingConverter<List<String>, String[]> {
2
3 @Override
4 public String[] convertSource(final List<String> list) {
5 if (list != null) {
6 return list.toArray(new String[list.size()]);
7 }
8 else {
9 return null;
10 }
11 }
12
13 @Override
14 public List<String> convertDestination(final String[] destinationValue) {
15 if (destinationValue != null) {
16 return new ArrayList<String>(Arrays.asList(destinationValue));
17 }
18 else {
19 return null;
20 }
21 }
22 }Dieser könnte wie folgt verwendet werden können:
1 final ObservableValue<List<String>> source = new ObservableValue<List<String>>(); 2 final ObservableValue<String[]> destination = new ObservableValue<String[]>(); 3 4 Bind.bind(source, destination, new ListArrayBindingConverter());
Der folgende JUnitTest demonstriert die Verwendung der Klasse
Bind. Der Test wurde etwas verkürzt, der
vollständige Test findet sich
hier:
1 public class BindingTest {
2
3 private static String STRING_1 = "STRING_1";
4 private static String STRING_2 = "STRING_2";
5 private static String STRING_3 = "STRING_3";
6 private static String STRING_4 = "STRING_4";
7 private static String STRING_5 = "STRING_5";
8 private static String STRING_6 = "STRING_6";
9 private static String STRING_7 = "STRING_7";
10 private static String STRING_8 = "STRING_8";
11 private static String STRING_9 = "STRING_9";
12 private static String STRING_10 = "STRING_10";
13
14 @Test
15 public void testBinding() {
16 //Create two observable values
17 final ObservableValue<String> source = new ObservableValue<String>(STRING_1);
18 final ObservableValue<String> destination = new ObservableValue<String>(STRING_2);
19
20 //create a new binding
21 final IBinding binding = Bind.bind(source, destination);
22
23 //must be equal and must be STRING_1 (source before binding)
24 testEquality(source, destination, STRING_1);
25
26 //change source must change destination
27 source.setValue(STRING_3);
28
29 //must be equal and STRING_3
30 testEquality(source, destination, STRING_3);
31
32 //change destination must change source
33 destination.setValue(STRING_4);
34
35 //must be equal and STRING_4
36 testEquality(source, destination, STRING_4);
37
38 //unbind the values
39 binding.unbind();
40
41 //after unbind, change source, destination changes not
42 source.setValue(STRING_5);
43 Assert.assertEquals(STRING_5, source.getValue());
44 Assert.assertEquals(STRING_4, destination.getValue());
45
46 //after unbind, change destination, source changes not
47 destination.setValue(STRING_6);
48 Assert.assertEquals(STRING_6, destination.getValue());
49 Assert.assertEquals(STRING_5, source.getValue());
50
51 //bind the values again
52 binding.bind();
53
54 //must be equal and STRING_5 (last source value)
55 testEquality(source, destination, STRING_5);
56 }
57
58 private void testEquality(
59 final IObservableValue<String> source,
60 final IObservableValue<String> destination,
61 final String expectedValue) {
62
63 //the values of the observable value must be equal
64 Assert.assertEquals(source.getValue(), destination.getValue());
65
66 //the source must be the expected value
67 Assert.assertEquals(expectedValue, source.getValue());
68
69 //the destination must be the expected value
70 Assert.assertEquals(expectedValue, destination.getValue());
71 }
72
73 }