我正在尝试在Kotlin写一个Vaadin应用程序。对于数据绑定,Vaadin 8现在提供了类型安全数据绑定的可能性。在Kotlin,我本来期待这样的工作:
class LoginModel {
var username: String = ""
var password: String = ""
}
class LoginView : FormLayout() {
val name = TextField("name")
val password = TextField("password")
val loginButton = Button("login")
init {
val binder = Binder<LoginModel>()
binder.forField(name).bind(
{ it.username },
{ bean, value -> bean.username = value })
//...
}
}
我在这里收到以下错误消息:
Error:(23, 31) Kotlin: Type inference failed: Not enough information to infer parameter BEAN in fun <BEAN : Any!, TARGET : Any!, BEAN : Any!> Binder.BindingBuilder<BEAN#1 (type parameter of bind), TARGET>.bind(p0: ((BEAN#1!) -> TARGET!)!, p1: ((BEAN#1!, TARGET!) -> Unit)!): Binder.Binding<BEAN#1!, TARGET!>!
Please specify it explicitly.
我尝试通过显式指定类型参数:
binder.forField(name).bind<LoginView, String, LoginView>(
{ it.username },
{ bean, value -> bean.username = value })
但是这会导致错误消息(和其他sytax错误,所以我没有遵循这种方法)
Error:(23, 35) Kotlin: No type arguments expected for fun bind(p0: ValueProvider<LoginModel!, String!>!, p1: Setter<LoginModel!, String!>!): Binder.Binding<LoginModel!, String!>! defined in com.vaadin.data.Binder.BindingBuilder
我的第二种方法是尝试直接传递Kotlin属性访问器,但错误消息与第一个相同:
binder.forField(name).bind(LoginModel::username.getter, LoginModel::username.setter)
最后一个方法是尝试使用扩展方法并尽可能明确地使用所有内容:
fun <BEAN, TARGET> Binder.BindingBuilder<BEAN, TARGET>.bind(property: KMutableProperty1<BEAN, TARGET>) {
fun set(bean: BEAN): TARGET = property.get(bean)
fun get(bean: BEAN, value: TARGET): Unit = property.set(bean, value)
this.bind(::set, ::get)
}
但它仍会导致与第一个
相同的错误消息答案 0 :(得分:3)
我已经尝试了你的例子,它与我的Intellij 2017.1.4和Kotlin 1.1.2-5编译得很好。可能你发现了旧版Kotlin插件中的一个错误?
方法bind
不使用通用参数,因此无法进行泛化。 forField
方法采用一个通用参数,因此您可以尝试
binder.forField<String>(name).bind(
{ it.username },
{ bean, value -> bean.username = value })
但首先,请确保您拥有最新版本的Kotlin插件,并且/或者可以尝试使用Intellij Community Edition。
但是,我建议您使用bind(String)
,因为其他绑定方法不能使用JSR303验证。您还可以定义以下扩展方法:
fun <BEAN, FIELDVALUE> Binder.BindingBuilder<BEAN, FIELDVALUE>.bind(prop: KMutableProperty1<BEAN, FIELDVALUE?>): Binder.Binding<BEAN, FIELDVALUE> =
bind(prop.name)
从代码binder.forField(name).bind(LoginModel::username)
中调用如下。有关更多示例,请参阅此处:https://github.com/mvysny/karibu-dsl/blob/master/example-v8/src/main/kotlin/com/github/vok/karibudsl/example/form/FormView.kt
答案 1 :(得分:1)
您必须使用API级别26+。此版本更改了View.findViewById()的签名 - 请参阅此处https://developer.android.com/preview/api-overview.html#fvbi-signature
findViewById的结果不明确,您需要提供类型:
例如:
val myTextView = findViewById(R.id.list) as TextView
变为
val myTextView = findViewById<TextView>(R.id.myTextView)
答案 2 :(得分:0)
由于您的模型非常简单,您可以通过Binder#bind(String propertyName)
方法
val binder = Binder<LoginModel>()
binder.forField(name).bind("username");