ListView and ListViewGrouped

Basic example ListView

View.ListView(
    itemSelected = (fun idx -> dispatch (ListViewSelectedItemChanged idx)),
    items = [
        View.TextCell("First ListView")
        View.TextCell("Second ListView")
        View.TextCell("Third ListView")
    ]
)

The itemSelected callback uses integers indexes for keys to identify the elements.

There is also a ListViewGrouped for grouped items of data. This uses the same Xamarin control under the hood but in a different mode of use.

Basic example ListViewGrouped

View.ListViewGrouped(
    itemSelected = (fun idx -> dispatch (ListViewSelectedItemChanged idx)),
    items = [
        "Group 1", View.TextCell "Group 1", [
            View.TextCell("First item")
            View.TextCell("Second item")
            View.TextCell("Third item")
        ]

        "Group 2", View.TextCell "Group 2", [
            View.TextCell("Fourth item")
            View.TextCell("Fifth item")
            View.TextCell("Sixth item")
        ]
    ]
)

See also:

More examples

“Infinite” or “unbounded” ListViews

“Infinite” (really “unbounded”) lists are created by using the itemAppearing event to prompt a message which nudges the underlying model in a direction that will then supply new items to the view.

For example, consider this pattern:

type Model =
    { ...
      LatestItemAvailable: int
    }

type Message =
    ...
    | GetMoreItems of int

let update msg model =
    match msg with
    | ...
    | GetMoreItems n -> { model with LatestItemAvailable = n }

let view model dispatch =
    ...
    View.ListView(
        itemAppearing = (fun idx -> if idx >= max - 2 then dispatch (GetMoreItems (idx + 10) ) ),
        items = [
            for i in 1 .. model.LatestItemAvailable do
                yield View.TextCell("Item " + string i)
        ]
    )
...

Note:

  • The underlying data in the model is just an integer LatestItemAvailable (normally it would really be a list of actual entities drawn from a data source)
  • On each update to the view we produce all the visual items from Item 1 onwards
  • The itemAppearing event is called for each item, e.g. when item 10 appears
  • When the event triggers we grow the underlying data model by 10
  • This will trigger an update of the view again, with more visual elements available (but not yet appearing)

Surprisingly even this naive technique is fairly efficient. There are numerous ways to make this more efficient (we aim to document more of these over time too). One simple one is to memoize each individual visual item using dependsOn:

items = [
    for i in 1 .. model.LatestItemAvailable do
        yield dependsOn i (fun model i -> View.Label("Item " + string i))
]

With that, this simple list views scale to > 10,000 items on a modern phone, though your mileage may vary. There are many other techniques (e.g. save the latest collection of visual element descriptions in the model, or to use a ConditionalWeakTable to associate it with the latest model). We will document further techniques in due course.

There is also an itemDisappearing event for ListView that can be used to discard data from the underlying model and restrict the range of visual items that need to be generated.