从视图模型绑定到 ListView 项目的点击属性

Posted

技术标签:

【中文标题】从视图模型绑定到 ListView 项目的点击属性【英文标题】:Binding to ListView item tapped property from View Model 【发布时间】:2014-11-20 08:22:13 【问题描述】:

我正在尝试使用 itemtapped 属性将事件绑定到菜单页面上的 ListView。目前我在我的应用程序中使用 MVVM (Xamarin form labs) 框架。我想要完成的是当用户点击应用程序导航到正确视图的菜单项时。

这里是 xaml 代码:

<ListView x:Name="list"
        ItemsSource="Binding MenuItems" 
        SelectedItem="Binding SelectedItem" 
        ItemTapped= SET-BINDING-HERE >
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <ViewCell.View>
          //setup template here
        </ViewCell.View>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate> 
</ListView>

我想将 itemtapped 事件绑定到这个函数:

public void NavigateTo(object sender, ItemTappedEventArgs args)
  
      var test = args.Item as MenuModel;
      cPageTypes.GetByKey(test.CommandParameter)
                .SwitchRootPage(AIMCore.ViewModels.ElliottBaseViewModel.MasterPage);
      list.SelectedItem = null;
      AIMCore.ViewModels.BaseViewModel.MasterPage.IsPresented = false;
  

如果我将函数添加到后面的视图代码中,然后设置 ItemTapped='NavigatTo',我目前可以让它工作,但这似乎是错误的,因为它违背了 MVVM 概念。我真正想做的是将事件绑定到我的 ViewModel 中的相同功能,如下所示:

<ListView x:Name="list"
        ItemsSource="Binding MenuItems" 
        SelectedItem="Binding SelectedItem" 
        ItemTapped= "Binding NavigateTo" > // this binding is to the ViewModel

但是这不起作用,或者我没有正确执行。当我尝试以这种方式实现它时,代码会产生并出错。

错误: Xamarin.Forms.Xaml.XamlParseException:在 Xamarin.Forms.Xaml.BaseValueNode.SetPropertyValue 找不到名称 ItemTapped 的属性

【问题讨论】:

【参考方案1】:

我遵循了相同的架构,并通过创建自定义列表控件并使用以下代码在我的视图模型中覆盖的命令创建了 1 个可绑定属性:

我的 PCL 中的自定义控件 [.cs] 页面

using System;
using System.Windows.Input;
using Xamarin.Forms;


namespace YourNS 

    public class ListView : Xamarin.Forms.ListView 

        public static BindableProperty ItemClickCommandProperty = BindableProperty.Create<ListView, ICommand>(x => x.ItemClickCommand, null);


        public ListView() 
            this.ItemTapped += this.OnItemTapped;
        


        public ICommand ItemClickCommand 
            get  return (ICommand)this.GetValue(ItemClickCommandProperty); 
            set  this.SetValue(ItemClickCommandProperty, value); 
        


        private void OnItemTapped(object sender, ItemTappedEventArgs e) 
            if (e.Item != null && this.ItemClickCommand != null && this.ItemClickCommand.CanExecute(e)) 
                this.ItemClickCommand.Execute(e.Item);
                this.SelectedItem = null;
            
        
    

我的 XAML 页面

<ContentPage ...
             xmlns:local="clr-namespace:Samples.Views;assembly=Your Assebly Name">

<local:ListView ItemClickCommand="Binding Select" 
        ItemsSource="Binding List">

在我的视图模型中[在这个例子中,我只打开了对话框操作表

private Command<Signature> selectCmd;
        public Command<Signature> Select 
            get 
                this.selectCmd = this.selectCmd ?? new Command<Signature>(s => 
                    this.dialogs.ActionSheet(new ActionSheetConfig()
                        .Add("View", () => 
                            if (!this.fileViewer.Open(s.FilePath))
                                this.dialogs.Alert(String.Format("Could not open file 0", s.FileName));
                        )
                        .Add("Cancel")
                    )
                );
                return this.selectCmd;
            
        

【讨论】:

我认为这是一个比我目前拥有的更好的解决方案,并且正在考虑开发类似的东西(尝试限制数量或呈现代码共享)。我还有一个问题,添加命令参数是否与添加项目单击命令相同?我希望能够将点击的项目传递给下一个视图。 对不起,我知道这是一个老问题,但我收到以下错误:“Xamarin.Forms.ListView”不包含“ItemClickCommand”的定义,并且没有扩展方法“ItemClickCommand”接受可以找到“Xamarin.Forms.ListView”类型的第一个参数(您是否缺少 using 指令或程序集引用?),有什么想法吗?我已经添加了所有相关参考,但智能感知没有显示 ItemClickCommand。谢谢。 @Thierry:您使用的是 还是 ? ItemClickCommand 未在 Xamarin.Forms 附带的内置 ListView 上定义。这里的答案是继承自 ListView 以创建自己的自定义 ListView 并带有一个名为 ItemClickCommand 的新属性。要使用它,您需要将正确的 xmlns 定义添加到 XAML 的顶部,并使用 或 ,其中 [whatever] 是您定义的 xmlns。 在 PCL 上对我来说工作得很好。 不要忘记对 CachingStrategy 的支持。当您填充了 CachingStrategy 属性时,您需要实现一个额外的构造函数来防止“.....ctor' not found”。 Xamarin 异常。将以下构造函数添加到您的自定义 ListView 代码。 public ListViewWithCommands(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy) ItemTapped += ListViewWithCommands_ItemTapped; 【参考方案2】:

您也可以使用附加行为

public static class ListViewAttachedBehavior

    public static readonly BindableProperty CommandProperty =
        BindableProperty.CreateAttached (
            "Command",
            typeof(ICommand),
            typeof(ListViewAttachedBehavior),
            null,
            propertyChanged:OnCommandChanged);

    static void OnCommandChanged (BindableObject view, object oldValue, object newValue)
    
        var entry = view as ListView;
        if (entry == null) 
            return;

        entry.ItemTapped += (sender, e) => 
            
                var command = (newValue as ICommand);
                if(command == null)
                    return;

                if(command.CanExecute(e.Item))
                
                    command.Execute(e.Item);
                

            ;
    

然后在你的 ListView 上调用它

 <ListView
        RowHeight="70"
        x:Name="AcquaintanceListView"
        b:ListViewAttachedBehavior.Command="Binding ItemSelectedCommand"
        ItemsSource="Binding Acquaintances">

【讨论】:

以上是关于从视图模型绑定到 ListView 项目的点击属性的主要内容,如果未能解决你的问题,请参考以下文章

无法在 ListView 中绑定分组属性

将 ListView 的 SelectedItems 绑定到 ViewModel

我应该在 Silverlight 项目中使用模型-视图-视图模型 (MVVM) 模式吗?

将属性绑定到 Xamarin 中的 ListView,不会更新视图

如何绑定到 ListView 中的模型而不是 WinUI3 中的属性?

WPF MVVM绑定窗口图标到视图模型中的属性