summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAlexander Neumann <alexander.neumann@picos-software.com>2020-08-31 15:45:34 +0200
committerAlexander Neumann <alexander.neumann@picos-software.com>2020-08-31 15:45:34 +0200
commitf6c18dbf6bd964bcd544fa602acb832567c215ad (patch)
tree8c2f5c8d0034c2b9fab0f2ad1d5c4c5ed465b268
parentTableView: Improve focus handling (diff)
downloadwireguard-windows-f6c18dbf6bd964bcd544fa602acb832567c215ad.tar.xz
wireguard-windows-f6c18dbf6bd964bcd544fa602acb832567c215ad.zip
ListBox: Add data binding support
-rw-r--r--declarative/listbox.go18
-rw-r--r--listbox.go106
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
}
diff --git a/listbox.go b/listbox.go
index cf274527..101ead3b 100644
--- a/listbox.go
+++ b/listbox.go
@@ -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