【问题标题】:How to properly bind to VM Properties from within a DataTemplate如何从 DataTemplate 中正确绑定到 VM 属性
【发布时间】:2022-01-05 08:52:27
【问题描述】:

问题:

我有一个带有ListView 的页面来显示对象列表。我按照微软的Creating a DataTemplate with a TypeDataTemplate 分离到它自己的文件中。我希望能够编辑或删除此列表中的条目,因此我一直使用ViewCellContextActions MenuItem 来提供此功能。这一直有效,直到我不得不将我的 DataTemplate 与ContentPage 分开。处理编辑和删除的命令驻留在我ContentPageBindingContext,也就是ViewModel

我尝试过的事情

多种格式绑定,FindAncestorBindingContextFindAncestorRelativeSource模式,多种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 时遇到了麻烦。使用上面的代码不会触发命令。出现上下文菜单并且按钮的文本是正确的,但是该命令要么永远不会执行,要么永远找不到ViewModelBindingContext。到目前为止,我唯一的解决方案是将DataTemplate 包含在ContentPage 中,这实际上违背了首先分离DataTemplate 的目的。任何帮助表示赞赏,谢谢!

更新和回答

ToolmakerSteve 很友好地链接了一个线程,虽然链接的答案不起作用,但线程接受的答案确实有效。出于某种原因,FindAncestor 在我的情况下不起作用,我必须通过 XAML 层次结构引用ViewModel。我不确定这是否是 MVVM 的好习惯,但它确实有效。

TL;DR:

要从分离的 DataTemplate 中引用您的 ViewModel,您必须遍历 XAML 层次结构。为此,请为您的DataTemplateViewCell 提供一个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


【解决方案1】:

@ToolmakerSteve 在 cmets 中提出的建议没有帮助,但是同一个线程的实际答案确实有帮助。我可以通过引用ViewCell 的父级而不是使用FindAncestor 来绑定到我的ViewModel

您必须为您的DataTemplateViewCell 提供一个x:Name 参数才能引用它。接下来是弄清楚在到达具有BindingContext 的元素之前必须遍历的层次结构多远 您正在寻找的对象。就我而言,我第一次选择上两个级别并且它起作用了。这是我修改后的绑定,其中VC 是我的ViewCellx:Name

{Binding Parent.Parent.BindingContext.EditCommand, Source={x:Reference VC}}

我觉得很奇怪FindAncestor 在这种情况下不起作用。也许这是一个错误?不管怎样,谢谢你的帮助。

【讨论】:

    猜你喜欢
    • 2011-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2016-05-06
    相关资源
    最近更新 更多