У меня есть mvp-структурированное приложение javafx. Существует представление с текстовым полем, которое имеет свой собственный textProperty типа StringProperty
. Существует также модель, которая содержит объект, называемый Item. Элемент имеет IntegerProperty
.
Теперь я хотел бы привязать эти два свойства в моем классе-презентаторе, чтобы они обновлялись, когда та или иная изменяется. Несмотря на то, что у них разные типы, существует возможность связать их следующим образом:
Bindings.bindBidirectional( textField.textProperty(), item.percentProperty(), new NumberStringConverter() );
Это работает отлично, если только значение текстового поля не будет очищено, что приведет к NullPointerException
, потому что пустое значение textProperty приводит к нулевому значению и установка нулевого значения в IntegerProperty
приводит к a NullPointerException
. Можете ли вы придумать любой способ избежать этого? Должен ли я написать свой собственный NumberStringConverter
?
Кроме того, я хотел бы определить, что Item
может содержать только процентное значение от 0 до 100. При значении недопустимое значение следует информировать, поэтому пользователь может получить обратную связь. Где я должен проверять эти бизнес-единицы?
Я придумал первый пример, но я не уверен, если это должно быть так, поэтому мне было бы любопытно, если бы у вас были лучшие идеи, как это решить.
class PercentProperty extends SimpleIntegerProperty
{
private InvalidValueListener invalidValueListener = null;
public PercentProperty ( final Integer defaultValue )
{
set( defaultValue );
}
@Override
public void set( final int newValue )
{
if ( isValid( newValue ) )
{
super.set( newValue );
if ( invalidValueListener != null )
invalidValueListener.validValue();
}
else
{
if ( invalidValueListener != null )
invalidValueListener.invalidValue();
}
}
private boolean isValid( final int value )
{
return (value >= 0 && value <= 100);//FIXME: Better use Predicates to define Rules.
}
public void setListener( final InvalidValueListener listener )
{
invalidValueListener = listener;
}
public void removeListener( @SuppressWarnings( "unused" ) final InvalidValueListener listener )
{
invalidValueListener = null;
}
protected void fireInvalidationValue()
{
invalidValueListener.invalidValue();
}
}
interface InvalidValueListener
{
void validValue();
void invalidValue();
}