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 }