【发布时间】:2022-01-05 08:52:27
【问题描述】:
问题:
我有一个带有ListView 的页面来显示对象列表。我按照微软的Creating a DataTemplate with a Type 将DataTemplate 分离到它自己的文件中。我希望能够编辑或删除此列表中的条目,因此我一直使用ViewCell 的ContextActions MenuItem 来提供此功能。这一直有效,直到我不得不将我的 DataTemplate 与ContentPage 分开。处理编辑和删除的命令驻留在我ContentPage的BindingContext,也就是ViewModel。
我尝试过的事情
多种格式绑定,FindAncestorBindingContext和FindAncestorRelativeSource模式,多种AncestorType
{Binding BindingContext.EditCommand, Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContentPage}}}
{Binding Source={RelativeSource Mode=FindAncestorBindingContext, AncestorType={x:Type views:LoginView}}, Path=EditCommand}
{Binding Source={RelativeSource AncestorType={x:Type vm:LoginVM}}, Path=BindingContext.EditCommand}
问题:
如何从分离的DataTemplate 绑定到我的ViewModel 中的命令? 我尝试使用RelativeSource 绑定,但该命令从未触发,或者祖先永远不会成立。这是我的基本设置:
内容页面(登录视图):
....
<ContentPage.BindingContext>
<vm:LoginVM x:Name="viewmodel"/>
</ContentPage.BindingContext>
<ContentPage.Content>
....
<Frame HasShadow="True" Padding="30" VerticalOptions="End" BackgroundColor="{DynamicResource PageBackgroundColor}">
<ListView ItemsSource="{Binding sessionList}" SelectedItem="{Binding SelectedItem}" HasUnevenRows="True" >
<ListView.ItemTemplate>
<DataTemplate>
<templates:LoginSessionTemplate/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
</ContentPage.Content>
数据模板:
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:PIM.View"
x:Class="PIM.DataTemplates.LoginSessionTemplate">
<ViewCell.ContextActions>
<MenuItem Command="{Binding Source={RelativeSource AncestorType={x:Type views:LoginView}}, Path=EditCommand}" CommandParameter="{Binding .}" Text="Edit"/>
</ViewCell.ContextActions>
....
模板和数据对象之间的绑定很好,我只是在分离的DataTemplate 中绑定到ViewModel 时遇到了麻烦。使用上面的代码不会触发命令。出现上下文菜单并且按钮的文本是正确的,但是该命令要么永远不会执行,要么永远找不到ViewModel 的BindingContext。到目前为止,我唯一的解决方案是将DataTemplate 包含在ContentPage 中,这实际上违背了首先分离DataTemplate 的目的。任何帮助表示赞赏,谢谢!
更新和回答
ToolmakerSteve 很友好地链接了一个线程,虽然链接的答案不起作用,但线程接受的答案确实有效。出于某种原因,FindAncestor 在我的情况下不起作用,我必须通过 XAML 层次结构引用ViewModel。我不确定这是否是 MVVM 的好习惯,但它确实有效。
TL;DR:
要从分离的 DataTemplate 中引用您的 ViewModel,您必须遍历 XAML 层次结构。为此,请为您的DataTemplate 的ViewCell 提供一个x:Name 参数,然后在绑定中使用该引用。绑定将访问ViewCell 的父母。绑定应该如下所示:
{Binding Parent.Parent.BindingContext.MyCommand, Source={x:Reference ViewCellName}}
我只需要更改DataTemplate
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:PIM.View"
x:Class="PIM.DataTemplates.LoginSessionTemplate"
x:Name="VC">
<ViewCell.ContextActions>
<MenuItem Command="{Binding Parent.Parent.BindingContext.EditCommand, Source={x:Reference VC}}" CommandParameter="{Binding .}" Text="Edit"/>
</ViewCell.ContextActions>
....
【问题讨论】:
-
尝试this answer,它会从 ContentPage 中找到 BIndingContext。
-
使用
ContentPage作为AncesetorType也不起作用。 -
与其在问题中编辑答案,不如将其作为答案发布,或编辑现有答案以包含它。
标签: listview xamarin.forms mvvm datatemplate