1

I am having an issue that I have spend way too much time trying to figure out. I can't get the OnChildClick listener to fire when one of the child items in my ExpandableListAdapter is clicked.

It was my understanding that the overridden OnChildClick event of the ViewCheckListActivity.cs file below should fire when one of the rows of the children are clicked. I'm sure that I am missing something silly, but was wondering if anyone had any experience and could point me in the right direction for getting this working.

Code is all listed below:

CheckListItem_Group.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/loGroup"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  android:minWidth="25px"
  android:minHeight="25px">
  <CheckedTextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_marginLeft="20px"
      android:paddingLeft="35dip"
      android:textStyle="bold"
      android:textSize="14dip"
      android:gravity="center_vertical"
      android:layout_gravity="right"
      android:drawableRight="?android:attr/listChoiceIndicatorMultiple"
      android:id="@+id/chkCheckList" />
</LinearLayout>

CheckListItem_Item.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loItem"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:minWidth="25px"
    android:minHeight="25px">
    <CheckedTextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20px"
        android:paddingLeft="35dip"
        android:textStyle="bold"
        android:textSize="14dip"
        android:gravity="center_vertical"
        android:layout_gravity="right"
        android:clickable="false"
        android:focusable="true"
        android:drawableRight="?android:attr/listChoiceIndicatorMultiple"
        android:id="@+id/chkCheckListItem" />
</LinearLayout>

ViewCheckListActivity.cs

public class ViewCheckListActivity : ExpandableListActivity
{
    private Int32? _checkListId;
    protected static DiversLogDao Dao;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        var checkListItems = Dao.GetCheckListItems(_checkListId.Value);

        var adapter = new CheckListItemAdapter(this, checkListItems);
        SetListAdapter(adapter);

        ExpandableListView.ChoiceMode = ChoiceMode.Multiple;
        ExpandableListView.SetOnChildClickListener(this);
    }

    public override bool OnChildClick (ExpandableListView parent, View v, int groupPosition, int childPosition, long id)
    {
        return base.OnChildClick (parent, v, groupPosition, childPosition, id);
    }
}

CheckListItemAdapter.cs

public class CheckListItemAdapter : BaseExpandableListAdapter
{
    private readonly List<Item> _checkListItems;
    public readonly Activity Context;

    public CheckListItemAdapter(Activity context, List<CheckListItem> checkListItems)
    {
        _checkListItems =
            checkListItems.Where(i => i.ParentId == null)
                .Select(i => new Item
                                    {
                                        Id = i.Id,
                                        Name = i.Name,
                                        Description = i.Description,
                                        ChildItems = checkListItems.Where(c => c.ParentId == i.Id)
                                            .Select(c => new ChildItem
                                                            {
                                                                Id = c.Id,
                                                                CheckListId = c.CheckListId,
                                                                ParentId = c.ParentId,
                                                                Name = c.Name,
                                                                Description = c.Description,
                                                                LastUpdated = c.LastUpdated,
                                                                Checked = false
                                                            }).ToList()
                                    }).ToList();
        Context = context;
    }

    public override View GetGroupView(int groupPosition, bool isExpanded, View convertView, ViewGroup parent)
    {
        if (convertView == null)
        {
            convertView = Context.LayoutInflater.Inflate(Resource.Layout.CheckListItem_Group, null) as LinearLayout;
        }

        if (convertView != null)
        {
            var checkList = convertView.FindViewById<CheckedTextView>(Resource.Id.chkCheckList);
            checkList.SetText(_checkListItems[groupPosition].Name, TextView.BufferType.Normal);
            checkList.Checked = _checkListItems[groupPosition].AllChildrenChecked();
        }

        return convertView;
    }

    public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
    {
        if(convertView == null)
        {
            convertView = Context.LayoutInflater.Inflate(Resource.Layout.CheckListItem_Item, parent, false) as LinearLayout;
        }

        if (convertView != null)
        {
            var checkListItem = convertView.FindViewById<CheckedTextView>(Resource.Id.chkCheckListItem);
            checkListItem.SetText(_checkListItems[groupPosition].ChildItems[childPosition].Name, TextView.BufferType.Normal);
            checkListItem.Checked = _checkListItems[groupPosition].ChildItems[childPosition].Checked;
            checkListItem.Tag = _checkListItems[groupPosition].ChildItems[childPosition];

            checkListItem.Click -= CheckListItemClick;
            checkListItem.Click += CheckListItemClick;
        }

        return convertView;
    }

    protected void CheckListItemClick(object sender, EventArgs e)
    {
        var chkItem = sender as CheckedTextView;

        if (chkItem == null) return;

        chkItem.Toggle();

        var childItem = chkItem.Tag as ChildItem;

        if (childItem == null) return;

        childItem.Checked = chkItem.Checked;
    }

    public override Object GetChild(int groupPosition, int childPosition)
    {
        return _checkListItems[groupPosition].ChildItems[childPosition];
    }

    public override long GetChildId(int groupPosition, int childPosition)
    {
        return _checkListItems[groupPosition].ChildItems[childPosition].Id;
    }

    public override int GetChildrenCount(int groupPosition)
    {
        return _checkListItems[groupPosition].ChildItems.Count();
    }

    public override Object GetGroup(int groupPosition)
    {
        return _checkListItems[groupPosition];
    }

    public override long GetGroupId(int groupPosition)
    {
        return _checkListItems[groupPosition].Id;
    }

    public override bool IsChildSelectable(int groupPosition, int childPosition)
    {
        return true;
    }

    public override int GroupCount
    {
        get { return _checkListItems.Count(); }
    }

    public override bool HasStableIds
    {
        get { return true; }
    }

    private class Item : Object
    {
        public Int32 Id { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }
        public List<ChildItem> ChildItems { get; set; } 

        public bool AllChildrenChecked()
        {
            return ChildItems.All(i => i.Checked);
        }
    }

    private class ChildItem : Object
    {
        public Int32 Id { get; set; }
        public Int32 CheckListId { get; set; }
        public Int32? ParentId { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }
        public DateTime LastUpdated { get; set; }
        public Boolean Checked { get; set; }
    }
}
4

2 回答 2

1

I tried to reproduce this myself, and as far as I can tell this is a bug in the current version of Mono for Android. I submitted a bug report to Xamarin with a repro app, and an equivalent app in Java that is working.

That said, there is another option for hooking into when an item is clicked that you can use. You can assign a handler for the Click event on the view in the GetChildView method of your adapter:

public override View GetChildView(int groupPosition, int childPosition, bool isLastChild, View convertView, ViewGroup parent)
{
    // ...existing code in this method...

    convertView.Click += delegate 
    {
        // do stuff
    };

    return convertView;
}
于 2012-05-14T01:04:17.260 回答
1

I was able to finally get this working. Here is what I did to get it working.

The first was to add the focusable attribute to the layouts items as shown below:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/loItem"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:focusable="false"
    android:minWidth="25px"
    android:minHeight="25px">
    <CheckedTextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20px"
        android:paddingLeft="35dip"
        android:textStyle="bold"
        android:textSize="14dip"
        android:gravity="center_vertical"
        android:layout_gravity="right"
        android:focusable="false"
        android:drawableRight="?android:attr/listChoiceIndicatorMultiple"
        android:id="@+id/chkCheckListItem" />
</LinearLayout>

And

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/loGroup"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  android:focusable="false"
  android:minWidth="25px"
  android:minHeight="25px">
  <CheckedTextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_marginLeft="20px"
      android:paddingLeft="35dip"
      android:textStyle="bold"
      android:textSize="14dip"
      android:gravity="center_vertical"
      android:layout_gravity="right"
      android:focusable="false"      
      android:drawableRight="?android:attr/listChoiceIndicatorMultiple"
      android:id="@+id/chkCheckList" />
</LinearLayout>

Doing that alone didn't fix the issue. The next thing is the removable of the click event added to the checkbox list.

checkListItem.Click -= CheckListItemClick;
checkListItem.Click += CheckListItemClick;

Doing those 2 changes allowed the event to propagate all the way up to the activity itself.

I just hope that this information will help someone else out in the future. Not sure if this is as designed or not.

Chaitanya Marvici

于 2012-05-14T05:56:25.060 回答