如何使用 MvxRecyclerView 在 MvvmCross 中实现 Recycler View

Sha*_*que 2 data-binding xamarin.android mvvmcross xamarin

在 MvvmCross 中,我在一个有效的 Activity 中有一个 android listview。

我在某处读到将 listView 更改为 recyclerView 就像在我的布局 .axml 文件中将 MvxListView 更改为 MvxRecyclerView 一样简单。尝试这给了我以下运行时异常:

Android.Views.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class Mvx.MvxRecyclerView
Run Code Online (Sandbox Code Playgroud)

使用 MvxRecyclerView 时,我必须在背后的代码或视图模型中做些什么不同的事情吗?下面是我的代码。

布局文件:

主文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Mvx.MvxRecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        android:id="@+id/words_listview"
        local:MvxItemTemplate="@layout/words_listview_row"
        local:MvxBind="ItemsSource Words" />
</LinearLayout> 
Run Code Online (Sandbox Code Playgroud)

words_listview_row.axml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:p1="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    p1:minWidth="25px"
    p1:minHeight="25px"
    p1:layout_width="match_parent"
    p1:layout_height="match_parent"
    p1:id="@+id/relativeLayout1"
    p1:background="#FFFFFF">
    <TextView
        p1:text="Word name"
        p1:layout_width="wrap_content"
        p1:layout_height="wrap_content"
        p1:id="@+id/headingTextView"
        p1:width="325dp"
        p1:textColor="#000000"
        p1:layout_alignParentLeft="true"
        p1:textSize="18sp"
        p1:paddingLeft="20dp"
        p1:paddingTop="15dp"
        local:MvxBind="Text Name" />
    <TextView
        p1:text="Word meaning"
        p1:layout_width="match_parent"
        p1:layout_height="wrap_content"
        p1:layout_below="@id/headingTextView"
        p1:id="@+id/detailTextView"
        p1:textColor="#8f949a"
        p1:layout_alignParentLeft="true"
        p1:textSize="16sp"
        p1:paddingLeft="20dp"
        p1:paddingRight="20dp"
        p1:paddingBottom="15dp"
        local:MvxBind="Text Meaning" />
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

WordViewModel.cs

using MvvmCross.Core.ViewModels;
using VocabBuilder.Core.Models;
using VocabBuilder.Core.Services.Interfaces;

namespace VocabBuilder.Core.ViewModels
{
    public class WordViewModel : MvxViewModel
    {
        private IWordService _wordService;

        public MvxObservableCollection<Word> Words { get; set; }

        public WordViewModel(IWordService wordService)
        {
            Words = new MvxObservableCollection<Word>();

            _wordService = wordService;

            Words.ReplaceWith(_wordService.GetAllWords());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

代码隐藏/ WordView.cs

using Android.App;
using Android.OS;
using MvvmCross.Droid.Views;
using VocabBuilder.Core.ViewModels;

namespace VocabBuilder.UI.Droid.Views
{
    [Activity(Label="Vocab Builder", MainLauncher=true)]
    public class WordView : MvxActivity<WordViewModel>
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.Main);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢。

编辑:

这是我的 Setup.cs 文件:

using Android.Content;
using MvvmCross.Core.ViewModels;
using MvvmCross.Droid.Platform;

namespace VocabBuilder.UI.Droid
{
    public class Setup : MvxAndroidSetup
    {
        public Setup(Context applicationContext) : base(applicationContext)
        {
        }

        protected override IMvxApplication CreateApp()
        {
            return new Core.App();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Igo*_*gor 5

好的,在用 MvxRecyclerView 替换 MvxListView 后,我让 RecyclerView 轻松工作。不确定你的实现有什么特别的问题,但我会给你我的花絮,你可以尝试一下。

我的 RecyclerView 位于从 MvxFragment 继承的 Fragment 中 - 与您的有点不同,但不应成为决定因素。以下是一些片段片段:

public class ListsFragment : MvxFragment<ListsViewModel>
{
   ...
   public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
   {
      base.OnCreateView(inflater, container, savedInstanceState);
      var view =  this.BindingInflate(Resource.Layout.fragment_listsfragment, null);   
      return view;
   }
   ...
}
Run Code Online (Sandbox Code Playgroud)

这是 fragment_listsfragment 的 axml:

<?xml version="1.0" encoding="utf-8"?>
<MvvmCross.Droid.Support.V7.RecyclerView.MvxRecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    app:MvxItemTemplate="@layout/item_list"
    app:MvxBind="ItemsSource Lists; ItemClick ShowListItemsCommand" />
Run Code Online (Sandbox Code Playgroud)

我确实在您的 ViewModel 实现中看到了一些不同 - 我的是这样的:

public class ListsViewModel : BaseViewModel
{
  ...
  private readonly IListService _listService;
  private ObservableCollection<Models.List> _lists;

  public ObservableCollection<Models.List> Lists
  {
    get { return _lists; }
    set
    {
      _lists = value;
      RaisePropertyChanged(() => Lists);
    }
  }

  public MvxCommand<Models.List> ShowListItemsCommand
  {
    get
    {
      return new MvxCommand<Models.List>(selectedList =>
      {
        ShowViewModel<ListItemsViewModel>
                (new { listId = selectedList.Id });
      });
    }
  }
  ...
  public override async void Start()
  {
    base.Start();
    await InitializeAsync();
  }

  protected override async Task InitializeAsync()
  {
    await _listService.InitializeAsync();
    Lists = (await _listService.GetListsAsync())
            .ToObservableCollection();
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。