diff options
author | Alexander Neumann <alexander.neumann@picos-software.com> | 2020-08-31 15:45:34 +0200 |
---|---|---|
committer | Alexander Neumann <alexander.neumann@picos-software.com> | 2020-08-31 15:45:34 +0200 |
commit | f6c18dbf6bd964bcd544fa602acb832567c215ad (patch) | |
tree | 8c2f5c8d0034c2b9fab0f2ad1d5c4c5ed465b268 | |
parent | TableView: Improve focus handling (diff) | |
download | wireguard-windows-f6c18dbf6bd964bcd544fa602acb832567c215ad.tar.xz wireguard-windows-f6c18dbf6bd964bcd544fa602acb832567c215ad.zip |
ListBox: Add data binding support
-rw-r--r-- | declarative/listbox.go | 18 | ||||
-rw-r--r-- | listbox.go | 106 |
2 files changed, 104 insertions, 20 deletions
diff --git a/declarative/listbox.go b/declarative/listbox.go index 5654a8bb..68fe763d 100644 --- a/declarative/listbox.go +++ b/declarative/listbox.go @@ -8,9 +8,7 @@ package declarative import ( "errors" -) -import ( "github.com/lxn/walk" "github.com/lxn/win" ) @@ -54,7 +52,9 @@ type ListBox struct { // ListBox AssignTo **walk.ListBox - DataMember string + BindingMember string + CurrentIndex Property + DisplayMember string Format string ItemStyler walk.ListItemStyler Model interface{} @@ -63,13 +63,16 @@ type ListBox struct { OnItemActivated walk.EventHandler OnSelectedIndexesChanged walk.EventHandler Precision int + Value Property } func (lb ListBox) Create(builder *Builder) error { var w *walk.ListBox var err error - if _, ok := lb.Model.([]string); ok && lb.DataMember != "" { - return errors.New("ListBox.Create: DataMember must be empty for []string models.") + if _, ok := lb.Model.([]string); ok && + (lb.BindingMember != "" || lb.DisplayMember != "") { + + return errors.New("ListBox.Create: BindingMember and DisplayMember must be empty for []string models.") } var style uint32 @@ -97,7 +100,10 @@ func (lb ListBox) Create(builder *Builder) error { w.SetFormat(lb.Format) w.SetPrecision(lb.Precision) - if err := w.SetDataMember(lb.DataMember); err != nil { + if err := w.SetBindingMember(lb.BindingMember); err != nil { + return err + } + if err := w.SetDisplayMember(lb.DisplayMember); err != nil { return err } @@ -19,11 +19,13 @@ import ( type ListBox struct { WidgetBase + bindingValueProvider BindingValueProvider model ListModel providedModel interface{} styler ListItemStyler style ListItemStyle - dataMember string + bindingMember string + displayMember string format string precision int prevCurIndex int @@ -105,6 +107,39 @@ func NewListBoxWithStyle(parent Container, style uint32) (*ListBox, error) { }, lb.CurrentIndexChanged())) + lb.MustRegisterProperty("Value", NewProperty( + func() interface{} { + index := lb.CurrentIndex() + + if lb.bindingValueProvider == nil || index == -1 { + return nil + } + + return lb.bindingValueProvider.BindingValue(index) + }, + func(v interface{}) error { + if lb.bindingValueProvider == nil { + if lb.model == nil { + return nil + } else { + return newError("Data binding is only supported using a model that implements BindingValueProvider.") + } + } + + index := -1 + + count := lb.model.ItemCount() + for i := 0; i < count; i++ { + if lb.bindingValueProvider.BindingValue(i) == v { + index = i + break + } + } + + return lb.SetCurrentIndex(index) + }, + lb.CurrentIndexChanged())) + succeeded = true return lb, nil @@ -351,7 +386,8 @@ func (lb *ListBox) SetModel(mdl interface{}) error { if _, ok := mdl.([]string); !ok { if badms, ok := model.(bindingAndDisplayMemberSetter); ok { - badms.setDisplayMember(lb.dataMember) + badms.setBindingMember(lb.bindingMember) + badms.setDisplayMember(lb.displayMember) } } } @@ -362,6 +398,7 @@ func (lb *ListBox) SetModel(mdl interface{}) error { } lb.model = model + lb.bindingValueProvider, _ = model.(BindingValueProvider) if model != nil { lb.attachModel() @@ -374,42 +411,83 @@ func (lb *ListBox) SetModel(mdl interface{}) error { return lb.ensureVisibleItemsHeightUpToDate() } -// DataMember returns the member from the model of the ListBox that is displayed -// in the ListBox. +// BindingMember returns the member from the model of the ListBox that is bound +// to a field of the data source managed by an associated DataBinder. +// +// This is only applicable to walk.ReflectListModel models and simple slices of +// pointers to struct. +func (lb *ListBox) BindingMember() string { + return lb.bindingMember +} + +// SetBindingMember sets the member from the model of the ListBox that is bound +// to a field of the data source managed by an associated DataBinder. +// +// This is only applicable to walk.ReflectListModel models and simple slices of +// pointers to struct. +// +// For a model consisting of items of type S, data source field of type T and +// bindingMember "Foo", this can be one of the following: +// +// A field Foo T +// A method func (s S) Foo() T +// A method func (s S) Foo() (T, error) +// +// If bindingMember is not a simple member name like "Foo", but a path to a +// member like "A.B.Foo", members "A" and "B" both must be one of the options +// mentioned above, but with T having type pointer to struct. +func (lb *ListBox) SetBindingMember(bindingMember string) error { + if bindingMember != "" { + if _, ok := lb.providedModel.([]string); ok { + return newError("invalid for []string model") + } + } + + lb.bindingMember = bindingMember + + if badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok { + badms.setBindingMember(bindingMember) + } + + return nil +} + +// DisplayMember returns the member from the model of the ListBox that is +// displayed in the ListBox. // // This is only applicable to walk.ReflectListModel models and simple slices of // pointers to struct. -func (lb *ListBox) DataMember() string { - return lb.dataMember +func (lb *ListBox) DisplayMember() string { + return lb.displayMember } -// SetDataMember sets the member from the model of the ListBox that is displayed -// in the ListBox. +// SetDisplayMember sets the member from the model of the ListBox that is +// displayed in the ListBox. // // This is only applicable to walk.ReflectListModel models and simple slices of // pointers to struct. // // For a model consisting of items of type S, the type of the specified member T -// and dataMember "Foo", this can be one of the following: +// and displayMember "Foo", this can be one of the following: // // A field Foo T // A method func (s S) Foo() T // A method func (s S) Foo() (T, error) // -// If dataMember is not a simple member name like "Foo", but a path to a +// If displayMember is not a simple member name like "Foo", but a path to a // member like "A.B.Foo", members "A" and "B" both must be one of the options // mentioned above, but with T having type pointer to struct. -func (lb *ListBox) SetDataMember(dataMember string) error { - if dataMember != "" { +func (lb *ListBox) SetDisplayMember(displayMember string) error { + if displayMember != "" { if _, ok := lb.providedModel.([]string); ok { return newError("invalid for []string model") } } - lb.dataMember = dataMember + lb.displayMember = displayMember if badms, ok := lb.model.(bindingAndDisplayMemberSetter); ok { - badms.setDisplayMember(dataMember) + badms.setDisplayMember(displayMember) } return nil |