2016-03-09 76 views
0

我有一個工作人員填充結果列表。一個ListView綁定到這個結果列表,並在它們可用時立即用部分結果填充。很棒!JavaFX DataBinding的行爲很奇怪

然後有一個按鈕可以處理列表中的項目。所以它應該被禁用,只要列表是空的。這適用於其他列表。但不是這個。

我已通過剝離UI組件並僅使用屬性來減少了示例。結果是一樣的。要麼有某種錯誤,要麼我不明白綁定是如何工作的。

我希望對此有所幫助。

只需將此代碼放入main()方法中,您應該會看到問題。我使用Java 1.8更新74

// a list of items, e.g. in a list view 
ReadOnlyObjectWrapper<ObservableList<String>> items = new ReadOnlyObjectWrapper<>(
      FXCollections.observableArrayList(new ArrayList<>())); 

// a button that is disabled if there are no items 
BooleanProperty disabled = new SimpleBooleanProperty(); 
disabled.bind(Bindings.createBooleanBinding(() -> Boolean.valueOf(items.get().isEmpty()), items)); 

// a list with results, e.g. from a worker 
ReadOnlyObjectWrapper<ObservableList<String>> results = new ReadOnlyObjectWrapper<>(
      FXCollections.observableArrayList(new ArrayList<>())); 
// the items are bound to the results (the list is showing partial result then) 
items.bind(results); 

// the button is still disabled 
System.out.println(disabled.get()); // expected true !WORKS! 

// add a result (should inform the items and the button) 
results.get().add("Hello"); 

// both list should be identical now 
System.out.println(results.get()); // expected [Hello] !WORKS! 
System.out.println(items.get()); // expected [Hello] !WORKS! 

// the button should not be disabled anymore 
System.out.println(disabled.get()); // expected false !FALIED! 

// try to re-bind the button 
disabled.unbind(); 
disabled.bind(Bindings.createBooleanBinding(() -> Boolean.valueOf(items.get().isEmpty()), items)); 
System.out.println(disabled.get()); // expected false !WORKS! 

回答

0

結合爲items只爲items完成。這意味着只有在您替換列表時纔會更新該值,但如果您只是對其進行修改,則該值不會更新。

要通知由items包裹在列表中的更改,需要每一個列表中被替換的時間屬性綁定到列表中的「emptyness條件」:

items.addListener((observable, oldValue, newValue)-> { 
    if (newValue == null) { 
     disabled.unbind(); 
     disabled.set(true); 
    } else { 
     disabled.bind(Bindings.isEmpty(newValue)); 
    } 
}); 

或更簡單 - 使用一個ListProperty

ListProperty<String> items = new SimpleListProperty<>(); 
disabled.bind(Bindings.isEmpty(items)); 

Bindings.createXYZBinding(callable, o1, 02, ..., oN)創建XYZBinding,用於緩存由返回的值當時它被評估。評價發生lazyly,即所述結合是髒和時:

  1. get被稱爲綁定對象上或
  2. 第一個監聽被添加到結合​​或
  3. 至少一個ChangeListener加入到和結合變髒

的結合是髒的,如果

  1. 該值尚未評估(初始狀態)
  2. 在創建綁定時添加到o1,...,oN的偵聽器中的一個接收到更改事件。

如果評估callback,則綁定再次變得乾淨(即不髒)。

綁定高速緩存callback評估的結果,並在調用get或需要將數據傳遞給ChangeListener時使用此結果。如果在評估之後緩存的值發生變化,則僅調用監聽器。

+0

我做了一些更多的測試,考慮到您的信息。其實是調用'項目。綁定(結果);'在我的代碼中改變'items'包裝的值。如果你在前後調用'items.get()',你會得到一個不同的值。所以任何綁定到由'items'包裝的列表都是無用的。如果我事後做,一切都會奏效。我沒有想到這一點,仍然不完全明白爲什麼。 – Future

+0

@未來:我在答案中加了幾行。我希望它們幫助你理解並且不會混淆你......基本綁定不會重新計算值,除非他們認爲它是根據依賴項上發生的事件進行的必要步驟,並且'Property's不會將偵聽器添加到包裹的值,除非它是一個特殊的屬性,比如'MapProperty','ListProperty'或'SetProperty' – fabian