2016-11-19 220 views
1

我在更大規模的應用程序中遇到了此問題,其中某些自定義綁定在源屬性的值更改時未更新。JavaFX自定義綁定不起作用

我設法寫了一個簡單的類來複制這個問題,我真的不明白爲什麼會發生這種情況。下面是一個簡單的測試,複製問題:

import javafx.beans.binding.BooleanBinding; 
import javafx.beans.binding.ObjectBinding; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 

public class TestingBindingsFx { 

    private final ObjectProperty<MyEvent> objectProperty = new SimpleObjectProperty<MyEvent>(this, "objectProperty"); 
    private final BooleanProperty booleanProperty = new SimpleBooleanProperty(this, "booleanProperty"); 

    private ObjectBinding<MyEvent> bindingObj; 
    private BooleanBinding bindingBool; 

    public TestingBindingsFx(ObjectProperty<String> selection) { 
    setupBindings(selection); 
    } 

    private void setupBindings(ObjectProperty<String> selection) { 
    bindingObj = createObjectBinding(selection); 
    bindingBool = createBooleanBinding(selection); 
    objectProperty.bind(bindingObj); 
    booleanProperty.bind(bindingBool); 
    } 

    private static ObjectBinding<MyEvent> createObjectBinding(ObjectProperty<String> selection) { 
    return new ObjectBinding<MyEvent>() { 
     { 
     super.bind(selection); 
     } 

     @Override 
     protected MyEvent computeValue() { 
     System.out.println("createObjectBinding called"); 
     MyEvent ve = selection.get() == null ? MyEvent.EVENT1 
      : MyEvent.EVENT2; 
     return ve; 
     } 
    }; 
    } 

    private static BooleanBinding createBooleanBinding(ObjectProperty<String> selection) { 
    return new BooleanBinding() { 
     { 
     super.bind(selection); 
     } 

     @Override 
     protected boolean computeValue() { 
     System.out.println("createBooleanBinding called"); 
     return selection.get() == null ? true : false; 
     } 
    }; 
    } 

    public static void main(String[] args) { 
    ObjClass objclass = new ObjClass(); 
    System.out.println("Instantiating TestingBindingsFx..."); 
    TestingBindingsFx fx = new TestingBindingsFx(objclass.selection); 

    objclass.selection.addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { 
     System.out.println("changed " + oldValue + "->" + newValue); 
     } 
    }); 

    System.out.println("Changing selection property values..."); 
    objclass.selection.set("Test 1"); 
    objclass.selection.set("Test 2"); 
    } 

    enum MyEvent { 
    EVENT1, 
    EVENT2; 
    } 

    static class ObjClass { 
    public final ObjectProperty<String> selection = new SimpleObjectProperty<String>(this, "selection"); 
    } 
} 

那麼運行這個後,我看到:

Instantiating TestingBindingsFx... 
createObjectBinding called 
createBooleanBinding called 
Changing selection property values... 
changed null->Test 1 
changed Test 1->Test 2 

當我期望看到像這樣:

Instantiating TestingBindingsFx... 
createObjectBinding called 
createBooleanBinding called 
Changing selection property values... 
changed null->Test 1 
createObjectBinding called 
createBooleanBinding called 
changed Test 1->Test 2 
createObjectBinding called 
createBooleanBinding called 

ChangeListener按預期工作(僅用於驗證目的),每次更改選擇屬性的值時都會調用它。

但是,自定義綁定永遠不會在第一次後更新,看着代碼,我不明白爲什麼。起初我認爲它可能與弱引用有關,但我甚至將綁定對象轉換爲類級變量,但沒有改變。

我覺得我可能會在這裏失去一些至關重要的東西,但在查看這段代碼2個小時後,我只是看不出爲什麼。 在我的實際應用程序中,它更加奇怪,因爲其中一個自定義綁定實際上可以正常工作。

回答

2

這是因爲JavaFX很懶惰,認真。

如果依賴關係失效,則將綁定視爲無效,並通知潛在更改。除非您添加ChangeListener或使用get來檢索該值,否則不會使用computeValue方法,因爲「沒有人想知道新值」。這可以提高性能。

綁定屬性使用InvalidationListener完成,屬性也會被懶惰地刷新。

你可以例如添加更改監聽器的屬性強制每次綁定無效時重新計算值:

private void setupBindings(ObjectProperty<String> selection) { 
    bindingObj = createObjectBinding(selection); 
    bindingBool = createBooleanBinding(selection); 
    objectProperty.bind(bindingObj); 
    booleanProperty.bind(bindingBool); 

    objectProperty.addListener((a,b,c)-> {}); 
    booleanProperty.addListener((a,b,c)-> {}); 
} 
+0

賓果,就是這樣!我知道我錯過了一些簡單的東西,我非常專注於不被稱爲的computeValue,它完全忘記了綁定的懶惰性質。我不需要強制重新計算,懶惰是完全正常的,我只是簡單地缺少在更改源屬性值後重新讀取測試代碼中的目標屬性。感謝你及時的答覆。 – mfc