2014-10-21 2 views
1

Java와 C#을 알고 있지만 속성 바인딩은 C# MVVM에서만 알 수 있습니다. JavaFX에서 속성 값 (예 : C#)에 대한 사용자 정의 getter 및 setter를 사용하여 속성 바인딩을 이해하려고합니다.JavaFX Binding Setter 컨벤션

public class ViewModel { 

    private StringProperty name; 

    public ViewModel() { 
     name = new SimpleStringProperty(); 
    } 

    public final String getName() { 
     return name.get(); 
    } 

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

    public StringProperty getNameProperty() { 
     return name; 
    } 
} 

public class Controller implements Initializable { 

    @FXML 
    private TextField nameField; 

    private final ViewModel viewModel; 

    public Controller() { 
     viewModel = new ViewModel(); 
    } 

    @Override 
    public void initialize(URL url, ResourceBundle resourceBundle) { 
     Bindings.bindBidirectional(nameField.textProperty(), 
       viewModel.getNameProperty()); 
    } 
} 

내가 추천 자바 빈즈를 따르는 경우/자바 FX가 다음 바인딩 시스템이 반사를 사용하는만큼 영리 것, 명명 규칙 있다는 인상했다 및 사용 (?) :

나는 다음과 같은 클래스를 만들었습니다 속성에 대한 내 사용자 정의 getter/setter. 하지만 내 뷰 모델 getter/setter는 사용되지 않습니다.

대신 바인딩은 내 상호 작용없이 직접 속성의 get/set 메서드를 사용합니다. 나는 나는 다음과 같은 코드를 사용할 수 있음을 읽을 수는 있지만 이것보다 더 좋은 방법이 있어야한다 :

name = new SimpleStringProperty() { 
    @Override public void set(String value) { 
     // do something... 
     super.set(value); 
    } 
}; 

내가 지정할 수있는 바인딩 내 속성을 설정/얻기 위해 사용해야하는 방법? 그리고 사이드 노트에서 어떻게 변경하지 않고 속성 (C#의 NotifyOfPropertyChange()가 변경되었음을 알릴 수 있습니까?

편집 :

내가 뭘하려고 좀 더 선택적 내 데이터 모델을 채 웁니다 나중에 값의 사용하려는 때문에, 내 속성으로 설정되고 끝나는 것과 같은 것입니다 (여기서는 생략).

C#에서는이 작업이 간단합니다. setter에 술어를 설정했습니다. 또한 다른 속성을 설정하는 것만으로 폼/마법사의 진행 상황을 조정할 수 있습니다.

public String Property { 
    get { return _property; } 
    set { 
     if(SomePredicate(value)) { 
      _property = value; 
      _nextButtonCommand.canExecute() = true; 
      // notify... 
     } 
    } 
} 
+0

편집 응답에 대한 답변이 업데이트되었습니다. –

답변

3

자바 FX 속성

당신의 ViewModel 클래스의 name 속성을 정의하는 규칙은이 :

몇 가지 변종이있다
public class ViewModel { 

    private StringProperty name; 

    public ViewModel() { 
     // parameters are owning bean, property name, and initial value, 
     // and are optional for the property convention 
     name = new SimpleStringProperty(this, "name", ""); 
    } 

    public final String getName() { 
     return name.get(); 
    } 

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

    // Note this method name: 
    public final StringProperty nameProperty() { 
     return name; 
    } 
} 

: 특히 당신이 일을 재정의 할하려는 경우 수정 자 final을 제거하고 nameProperty()에서 this.name을 get 및 se의 this.nameProperty()으로 바꿀 수 있습니다. t 방법. 요점은 setName(...)을 호출 할 때 항상 nameProperty().set(...)과 동일한 결과를 제공하는지 확인하는 것입니다 (get 메소드와 마찬가지로).

귀하의 일반적인 해석은 어쨌든 한 레벨 씩 떨어져 있다고 생각합니다. StringProperty 클래스는 getset 메서드를 정의하며 이러한 메서드는 바인딩 때문에 자동으로 호출되는 메서드입니다. 따라서 약간 비표준 명명 규칙이 있지만 텍스트 필드에 입력하면 속성 값이 업데이트됩니다. 바인딩 API는 내가 아는 한 (많이?) 리플렉션을 사용하지 않습니다. 단순히 리스너를 속성에 등록하고 다른 리스너가 변경되면 바인딩을 업데이트합니다.

사용자 정의 게터 및 설정자는 실제로 사용자가 보여준 재정의 기술로 속성 클래스에만 지원됩니다. 그래도 실제로는 좋은 사용 사례를 찾지 못했습니다. 특히 바인딩 API를 사용하면 종속 값을 매우 쉽게 생성 할 수 있습니다.

업데이트

그래서 특정 예를 들어, 나는 다음과 같은 라인을 따라 그것을 구현하는 것이 :

public class ViewModel { 
    private StringProperty name = new SimpleStringProperty(this, "name"); 
    // usual JavaFX Property methods... 
} 

를 그런 다음, 필요한 장소 : 다음

Predicate<String> predicate = ... ; 
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.test(viewModel.getName()), 
    viewModel.nameProperty()); 

와 당신 할 수있는 일은

술어가 변경 될 경우, 당신도 할 수있는 10

ObjectProperty<Predicate<String>> predicate = new SimpleObjectProperty<>(s -> true); 
BooleanBinding canExecute = Bindings.createBooleanBinding(() -> 
    predicate.get().test(viewModel.getName()), 
    predicate, viewModel.nameProperty()); 

이 바인딩을 만들기위한 Bindings class 많은, 많은 공장 방법이 있으며, 필요한 경우 당신은 또한 추상적 ObjectBinding, StringBinding 등 클래스를 하위 클래스 .

이 접근법과 질문에서 제안 된 접근법 사이의 철학에는 미묘한 변화가 있습니다. 질문의 접근 방식 (하위 클래스 SimpleStringProperty)에서 동작을 실행할 수 있는지를 결정하는 논리는 string 속성에 의해 유지됩니다. 이 접근법에서는 문자열 속성 (실제로 문자열 속성에 WeakInvalidationListener을 등록하는 바인딩을 통해)을 관찰하는 다른 객체로 분해됩니다.

알림

당신은 속성 InvalidationListeners 또는 ChangeListeners을 등록 할 수 있습니다. addListener(InvalidationListener) 메서드는 Observable에서 상속되며 마지막으로 관찰 된 값이 더 이상 유효하지 않을 수 있음을 나타냅니다. 이것은 "게으른 평가"관측 값을 허용합니다. 관측 값은 요구 될 때만 새로운 값을 계산합니다. addListener(ChangeListener) 메서드는 ObservableValue에서 상속되며, 이름에서 알 수 있듯이 명시 적으로 값을 래핑하는 관찰 가능 항목입니다. ChangeListener을 등록하면 청취자에게 새 값이 통지되므로 열심히 평가해야합니다. API는 내 취향에 맞추기에는 너무 세밀하지만, 고성능 구현을 위해 많은 유연성을 제공합니다.

테스트 응용 프로그램에 따라서

, 당신은

viewModel.nameProperty().addListener(new ChangeListener<String>() { 
    @Override 
    public void changed(ObservableValue<? extends String> obs, String oldValue, String newValue) { 
     System.out.println("Name changed from "+oldValue+" to "+newValue); 
    } 
}); 

을하거나, 자바 8,

viewModel.nameProperty().addListener((obs, oldName, newName) -> 
    System.out.println("Name changed from "+oldValue+" to "+newValue)); 

의 차이 광막 더 간결을 무효화 리스너 사이에 당신 경우에만 분명해집니다 청취자를 변경할 수 있습니다 계산에 따라 달라지는 ObservableValue이 있어야합니다. 같은 코드로

IntegerProperty x = new SimpleIntegerProperty(2); 
IntegerProperty y = new SimpleIntegerProperty(3); 
ObservableNumberValue sum = x.add(y); 

sum.addListener(obs -> System.out.println("Invalidated")); // invalidation listener 
x.set(3); 
y.set(5); 

을하지만, 변경 청취자와 : 비교 대신 무효화 리스너의

sum.addListener((obs, oldSum, newSum) -> System.out.println("Changed")); 

합니다.

tutorial에 자세한 내용이 있습니다.