从视图函数创建Xamarin.Forms.DataTemplate

从视图函数创建Xamarin.Forms.DataTemplate,xamarin.forms,f#,Xamarin.forms,F#,CollectionView或ListView提供了一种查看T类型对象序列的方法。与StackLayout或Grid相比,它的优点是只在需要时加载视图 为每个对象指定视图的自然方式是提供函数v:T->view F 但是,CollectionView/ListView需要一个数据模板。API与绑定紧密相连,因此API不自然、不提供信息且类型不安全。有用的属性似乎是IDictionary类型的值 有没有可能绕过这个API,创建一个接受v:T->视图并返回数据模板的函数?这将允许为DataTempla

CollectionView或ListView提供了一种查看T类型对象序列的方法。与StackLayout或Grid相比,它的优点是只在需要时加载视图

为每个对象指定视图的自然方式是提供函数v:T->view F

但是,CollectionView/ListView需要一个数据模板。API与绑定紧密相连,因此API不自然、不提供信息且类型不安全。有用的属性似乎是IDictionary类型的值


有没有可能绕过这个API,创建一个接受v:T->视图并返回数据模板的函数?这将允许为DataTemplate以及ListView和CollectionView创建一个干净的API。

解决方案是使用DataTemplateSelector

以下是此网站的链接:-


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

实现这一点的一种方法是创建自己的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.xamarin表单中找到

不同之处在于元素具有自己的视图创建功能。因此,无需扩展DataTemplate来传递函数


此外,您还可以使用Xamarin.Forms的BindableLayout将任何网格或StackLayout转换为使用DataTemplate。。您似乎建议DataTemplates/DataTemplateSelector可以表示任意函数,尤其是图灵完全函数。我对此表示怀疑,因为DataTemplateSelector甚至不是递归的。但即使这是真的,它也需要对视图函数v进行反向工程,结果会导致非常复杂和不可概括的代码。NB Xaml与这个问题无关。一种方法是:1。创建一个类型BindContainert:T=member this.Contents=T,其中内容被更改为可绑定的友好内容。2.与其作为项传入一个T列表,不如传入一个BindContainer列表,将此列表转换为一个可观察集合,使其易于绑定。3.使用创建ContentView的函数定义DataTemplate,使用.SetBindingContentView.ContentProperty、Contents在其上设置绑定并返回它。如果以前在代码中使用过绑定的人能够充实/简化这个想法,那就太好了。