使用MvxExpandableListView

时间:2015-07-16 13:39:11

标签: android xamarin xamarin.android mvvmcross mvxbind

我希望在我写的Xamarin.Android应用程序中实现MvxExpandableListView的使用。我也在使用MvvmCross。我可以让ListView显示标题列表,但当用户尝试展开标题时应用程序会爆炸。

View的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/backgroundAssignmentTasks"
        android:alpha="0.7"
        android:src="@drawable/background" />
    <Mvx.MvxExpandableListView
        android:id="@+id/listAssignmentTasks"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:layout_margin="16dp"
        android:dividerHeight="7dp"
        android:divider="@drawable/list_divider"
        local:GroupItemTemplate="@layout/list_assignment_header"
        local:MvxItemTemplate="@layout/list_assignment_detail"
        local:MvxBind="ItemsSource Tasks; ItemClick AssignmentSelectedCommand" />
</RelativeLayout>

标题的布局文件

<?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:id="@+id/layoutTaskName"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/specific_lightgrey">
    <TextView
        android:id="@+id/assignmentTaskName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black"
        android:textSize="18dp"
        android:layout_marginLeft="32dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        local:MvxBind="Text Title" />
</LinearLayout>

细节布局

<?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:id="@+id/layoutTaskDescription"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/specific_darkgrey"
    android:visibility="visible">
    <TextView
        android:id="@+id/assignmentTaskDescription"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:textColor="@android:color/black"
        android:textSize="18dp"
        android:layout_margin="8dp"
        android:lines="4"
        local:MvxBind="Text Description" />
    <Button
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:layout_gravity="center"
        android:id="@+id/buttonRecordVideo"
        android:textColor="@android:color/white"
        android:textSize="18dp"
        android:text="Record"
        android:background="@color/specific_red" />
    </LinearLayout>

我的ViewModel提供以下列表

    private List<Assignment> _tasks;
    public List<Assignment> Tasks
    {
        get { return _tasks; }
        set {
            _tasks = value;
            RaisePropertyChanged ("Tasks");
        }
    }

抛出的异常是

[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] System.ArgumentNullException: Argument cannot be null.
[MonoDroid] Parameter name: source
[MonoDroid] at System.Linq.Check.Source (object) <IL 0x00010, 0x0005f>
[MonoDroid] at System.Linq.Enumerable.Cast<object> (System.Collections.IEnumerable) <0x0002b>
[MonoDroid] at Cirrious.MvvmCross.Binding.Droid.Views.MvxExpandableListAdapter.GetChildrenCount (int) <IL 0x0000c, 0x000e7>
[MonoDroid] at Android.Widget.IExpandableListAdapterInvoker.n_GetChildrenCount_I (intptr,intptr,int) [0x00009] in /Users/builder/data/lanes/1879/5f55a9ef/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.Widget.IExpandableListAdapter.cs:295
[MonoDroid] at (wrapper dynamic-method) object.4fad6314-d1a6-41b1-be64-97483d3976ab (intptr,intptr,int) <IL 0x00017, 0x0002f>

这让我相信我需要编写MvxExpandableListAdapter的实现。

如何将其链接到我的ViewModel和/或布局文件?

2 个答案:

答案 0 :(得分:1)

当你夸大布局时,它看起来像你的“任务”属性的null。 确保例如在构造函数值中指定_tasks。

public ViewModelCtor() {
    _tasks = new List<Assignment>();
}

答案 1 :(得分:1)

MvxExpandableListView的ItemsSource属性绑定到一组项目。展开组时,它需要该组的项目列表。

它尝试将组强制转换为Enumerable。那失败了,因为你的Assignment类不是列表。

你可以做的是继承IEnumerable,如下所示:

public class Assignment : IEnumerable<Assignment>
{

    public IEnumerator<Assignment> GetEnumerator()
    {
        return (new List<Assignment> { this }).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

这样,当您展开时,它会向您显示标题下方的一个项目。但是MvxExpandableListView实际上用于显示组内的列表而不是可折叠的标题/详细信息视图。

我认为你真正想要的是一个扩展并显示描述和记录按钮的视图。我有完全相同的问题,最终得到了这个。

  • 使用简单的MvxListView
  • 您的ItemTemplate将包含说明和记录按钮
  • 当用户点按标题时,说明和按钮会显示/消失

在视图布局中:

<Mvx.MvxListView
        android:id="@+id/listAssignmentTasks"
        local:MvxBind="ItemsSource CommentList.Result"
        local:MvxItemTemplate="@layout/list_assignment_item"
        local:MvxBind="ItemsSource Tasks"
         />

list_assignment_item模板:

<?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:id="@+id/layoutTaskName" ...>
  <TextView
      android:id="@+id/assignmentTaskName"
      ...
      local:MvxBind="Text Title; Click ToggleDetails" />
  <TextView
        android:id="@+id/assignmentTaskDescription"
        ...
        local:MvxBind="Text Description; Click ToggleDetails; Visibility DetailsVisible, Converter=Visibility" />
  <Button
      android:id="@+id/buttonRecordVideo"
      ...
      local:MvxBind="Visibility DetailsVisible, Converter=Visibility" />
</LinearLayout>

在Assignment视图模型中,创建DetailsVisible属性和ToggleDetails命令:

public class Assignment
{
    private bool detailsVisible;
    /*....*/
    public bool DetailsVisible
    {
        get
        {
            return this.detailsVisible;
        }
        set
        {
            this.detailsVisible = value;
            this.RaisePropertyChanged(() => DetailsVisible);
        }
    }

    public void ToggleDetails()
    {
        this.DetailsVisible = !this.DetailsVisible;
    }
}

可见性转换器

public class VisibilityValueConverter : MvxValueConverter<bool>
{
    protected override object Convert(bool value, Type targetType, object parameter, CultureInfo culture)
    {
        return value ? ViewStates.Visible : ViewStates.Gone;
    }
}