如何从 DataTemplate 中正确绑定到 VM 属性
How to properly bind to VM Properties from within a DataTemplate
问题:
我有一个带有 ListView
的页面来显示 object 的列表。我根据 Microsoft 的 Creating a DataTemplate with a Type 将 DataTemplate
分离到它自己的文件中。我希望能够编辑或删除此列表中的条目,因此我一直在使用 ViewCell
的 ContextActions
MenuItem
来提供此功能。这一直有效,直到我不得不将我的 DataTemplate 与 ContentPage
分开。处理编辑和删除的命令位于我的 ContentPage
的 BindingContext
,即 ViewModel
.
我试过的东西
多种绑定格式,FindAncestorBindingContext
和FindAncestor
两种RelativeSource
模式,多种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>
....
模板和数据 object 之间的绑定很好,我只是在从分离的 DataTemplate
中绑定到 ViewModel
时遇到了麻烦。使用上面的代码不会触发命令。出现上下文菜单并且按钮的文本是正确的,但是该命令从未执行或从未找到 ViewModel
的 BindingContext
。到目前为止,我唯一的解决方案是将 DataTemplate
包含在 ContentPage
中,这实际上违背了首先将 DataTemplate
分开的目的。感谢任何帮助,谢谢!
更新与回答
ToolmakerSteve 非常友好地 link 了一个话题,虽然 linked 的答案没有用,但被接受的话题答案确实有效。由于某种原因 FindAncestor
在我的情况下不起作用,我必须通过 XAML 层次结构引用 ViewModel
。我不确定这对 MVVM 来说是否是好的做法,但它确实有效。
TL;DR:
要从分离的 DataTemplate
中引用您的 ViewModel
,您必须遍历 XAML 层次结构。为此,请为您的 DataTemplate
的 ViewCell
提供一个 x:Name
参数,然后在您的绑定中使用引用。该绑定将访问 ViewCell
的 parents。绑定应如下所示:
{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>
....
@ToolmakerSteve 在评论中提出的建议没有帮助,但同一个线程的实际答案确实有帮助。我能够通过引用 ViewCell
的父级而不是使用 FindAncestor
.
来绑定到我的 ViewModel
您必须给 DataTemplate
的 ViewCell
一个 x:Name
参数才能引用它。接下来是找出在到达具有 BindingContext
的元素之前必须遍历多远的层次结构
您正在寻找的对象。就我而言,我第一次选择了两个级别,并且成功了。这是我修改后的绑定,其中 VC
是我的 ViewCell
的 x:Name
.
{Binding Parent.Parent.BindingContext.EditCommand, Source={x:Reference VC}}
我觉得很奇怪 FindAncestor
在这种情况下不起作用。也许这是一个错误?不管怎样,谢谢你的帮助。
问题:
我有一个带有 ListView
的页面来显示 object 的列表。我根据 Microsoft 的 Creating a DataTemplate with a Type 将 DataTemplate
分离到它自己的文件中。我希望能够编辑或删除此列表中的条目,因此我一直在使用 ViewCell
的 ContextActions
MenuItem
来提供此功能。这一直有效,直到我不得不将我的 DataTemplate 与 ContentPage
分开。处理编辑和删除的命令位于我的 ContentPage
的 BindingContext
,即 ViewModel
.
我试过的东西
多种绑定格式,FindAncestorBindingContext
和FindAncestor
两种RelativeSource
模式,多种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>
....
模板和数据 object 之间的绑定很好,我只是在从分离的 DataTemplate
中绑定到 ViewModel
时遇到了麻烦。使用上面的代码不会触发命令。出现上下文菜单并且按钮的文本是正确的,但是该命令从未执行或从未找到 ViewModel
的 BindingContext
。到目前为止,我唯一的解决方案是将 DataTemplate
包含在 ContentPage
中,这实际上违背了首先将 DataTemplate
分开的目的。感谢任何帮助,谢谢!
更新与回答
ToolmakerSteve 非常友好地 link 了一个话题,虽然 linked 的答案没有用,但被接受的话题答案确实有效。由于某种原因 FindAncestor
在我的情况下不起作用,我必须通过 XAML 层次结构引用 ViewModel
。我不确定这对 MVVM 来说是否是好的做法,但它确实有效。
TL;DR:
要从分离的 DataTemplate
中引用您的 ViewModel
,您必须遍历 XAML 层次结构。为此,请为您的 DataTemplate
的 ViewCell
提供一个 x:Name
参数,然后在您的绑定中使用引用。该绑定将访问 ViewCell
的 parents。绑定应如下所示:
{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>
....
@ToolmakerSteve 在评论中提出的建议没有帮助,但同一个线程的实际答案确实有帮助。我能够通过引用 ViewCell
的父级而不是使用 FindAncestor
.
ViewModel
您必须给 DataTemplate
的 ViewCell
一个 x:Name
参数才能引用它。接下来是找出在到达具有 BindingContext
的元素之前必须遍历多远的层次结构
您正在寻找的对象。就我而言,我第一次选择了两个级别,并且成功了。这是我修改后的绑定,其中 VC
是我的 ViewCell
的 x:Name
.
{Binding Parent.Parent.BindingContext.EditCommand, Source={x:Reference VC}}
我觉得很奇怪 FindAncestor
在这种情况下不起作用。也许这是一个错误?不管怎样,谢谢你的帮助。