【问题标题】:Creating a Xamarin.Forms.DataTemplate from a view function从视图函数创建 Xamarin.Forms.DataTemplate
【发布时间】:2019-08-26 06:50:35
【问题描述】:

CollectionView(或 ListView)提供了一种查看对象序列(T 类型)的方法。与 StackLayout 或 Grid 相比,它的优势在于仅根据需要加载视图。

为每个对象指定视图的自然方法是提供一个函数v:T->View (F#)。

但是 CollectionView/ListView 需要 DataTemplateDataTemplate class 与绑定非常相关,因此 API 是不自然的、无信息的和类型不安全的。有用的属性似乎是Values,类型为IDictionary<BindableProperty,Object>

是否有可能绕过这个 API 并创建一个接受 v:T->View 并返回 DataTemplate 的函数?这将允许为 DataTemplate 以及 ListView 和 CollectionView 创建一个干净的 API。

【问题讨论】:

  • 一种方法是: 1. 创建一个type BindContainer<T>(t:T) = member this.Contents = t,其中内容被更改为可绑定友好的东西。 2. 不是传入T 的列表作为项目,而是传入BindContainer<T> 的列表,将此列表转换为ObservableCollection(可绑定友好)。 3. 使用创建ContentView 的“函数”定义DataTemplate,使用.SetBinding(ContentView.ContentProperty,"Contents") 在其上设置绑定,然后返回它。如果以前在代码中使用过绑定的人可以充实/简化这个想法,那就太好了。

标签: xamarin.forms f#


【解决方案1】:

实现此目的的一种方法是创建您自己的 DataTemplate 和 ViewCell。

DataTemplate 只需要一个派生自 ViewCell 的类型,以便在 ListView 需要时进行实例化。 然后它调用这个新创建/重用的 ViewCell 的OnBindingContextChanged 方法并传递元素的相应值。

此时,您可以访问ViewCell.View 属性,该属性将包含您要显示的控件。 你可以在那个时候执行你的函数。

在你的情况下,因为你有一个'T 的列表,这将是这样的:

type FuncViewCell(createFunc: 'T -> View) =
    inherit ViewCell()

    override x.OnBindingContextChanged () =
        let data = x.BindingContext :?> 'T
        x.View <- createFunc data

type FuncDataTemplate(createFunc: 'T -> View) =
    inherit DataTemplate(fun () -> FuncViewCell(createFunc))


(...)

let createViewForData data =
    Button(Text = data.Text)

let listView = ListView()
listView.ItemTemplate <- FuncDataTemplate(createViewForData)
listView.ItemsSource <- dataSource

----

Or even directly:

type FuncListView(createFunc) =
    inherit ListView(DataTemplate = FuncDataTemplate(createFunc))

let listView = FuncListView(createViewForData)
listView.ItemsSource <- dataSource

在 Fabulous.XamarinForms 中可以找到类似的方法。

不同的是元素自带了自己的视图创建功能。所以不需要扩展 DataTemplate 来传递函数。

https://github.com/fsprojects/Fabulous/blob/79c5df748fff7a108dfbcbf8609cb2265a8fddc7/Fabulous.XamarinForms/src/Fabulous.XamarinForms.Core/CustomControls.fs#L110-L151

【讨论】:

    【解决方案2】:

    解决方案是使用 DataTemplateSelector。

    这里是这个链接:-

    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector

    您可以做的是从 API 调用中获取 DataTemplate Id,然后根据 Id,您可以选择特定的 DataTemplate。您将制作那么多 DataTemplate 并存储在页面的 Xaml 中。这将是最安全和最简单的解决方案。

    【讨论】:

    • 另外,您可以通过为 Xamarin.Forms 使用 BindableLayout 将任何 Grid 或 StackLayout 转换为使用 DataTemplate。docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/…
    • 您似乎在暗示 DataTemplates/DataTemplateSelectors 可以表示任意函数,尤其是图灵完备的。我对此持怀疑态度,因为 DataTemplateSelector 甚至不是递归的。但即使这是真的,它也需要对视图函数v 进行逆向工程,结果会导致非常复杂且不可通用的代码。 (NB Xaml 与这个问题无关。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2022-12-07
    • 1970-01-01
    • 1970-01-01
    • 2016-01-24
    相关资源
    最近更新 更多