0
votes

I have an MvxListView that properly works and displays the information I need. I even have my ItemClick commands working properly. What I can't figure out right now is how to get the view cell that the user clicked on. I would like to expand the view cell that the user clicked on. Here are some code examples of what I'm working with:

ViewModel:

    private List<ContactItemEncrypted> _contactsEncryted;
    public List<ContactItemEncrypted> ContactsEncrypted
    {
        get { return _contactsEncryted; }
        set { _contactsEncryted = value; RaisePropertyChanged(() => ContactsEncrypted); }
    }

    private MvxCommand<ContactItemDecrypted> _itemSelectedCommand;
    public System.Windows.Input.ICommand ItemSelectedCommand
    {
        get
        {
            _itemSelectedCommand = _itemSelectedCommand ?? new MvxCommand<ContactItemDecrypted>(DoSelectItem);
            return _itemSelectedCommand;
        }
    }

    private void DoSelectItem(ContactItemDecrypted item)
    {
        var message = new ContactSelectedMessage(this, item);
        _messenger.Publish(message);
    }

View:

[Activity(
    Label = "Contacts",
    Theme = "@style/AppTheme",
    ScreenOrientation = ScreenOrientation.Portrait
)]
public class ContactsListView : MvxAppCompatActivity
{
    private MvxListView _listView;
    private MvxSubscriptionToken _tokenContactSelected;

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.ContactsListScreen);

        _listView = FindViewById<MvxListView>(Resource.Id.contactListView);

        var messenger = Mvx.Resolve<IMvxMessenger>();

        _tokenContactSelected = messenger.SubscribeOnMainThread<ContactSelectedMessage>(ContactSelected);
    }

    private void ContactSelected(ContactSelectedMessage obj)
    {
        ExpandView(_listView.Adapter.GetPosition(obj.SelectedContact));
    }

    private void ExpandView(int index)
    {
        itemLayout.Visibility = ViewStates.Visible;
    }
}

The Layout with the listview:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">
<Mvx.MvxListView
    android:id="@+id/contactListView"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    local:MvxBind="ItemsSource ContactsDecrypted; ItemClick ItemSelectedCommand; ItemLongClick ItemLongClickCommand"
    local:MvxItemTemplate="@layout/contactlistviewitemtemplate" />
</FrameLayout>

And the ItemTemplate layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minWidth="25px"
android:minHeight="25px">
<TextView
    android:id="@+id/textViewName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="18dp"
    android:textColor="@color/black"
    android:layout_margin="14dp"
    custom:MvxBind="Text FullName" />
</LinearLayout>

Please bare in mind that I don't have the code written out that expands the view yet. I don't want to start on that until I actually have the view I can work with.

Thank you.

3

3 Answers

1
votes

You need to implement AdapterView.IOnItemClickListener in ContactsListView so you can receive the item that is clicked.

However this needs some customization because implementing AdapterView.IOnItemClickListener seems to cancel out the MvvmCross binding of ICommand.

Looking at the code of MvxListView we can see the code used to invoke an item ICommand:

protected virtual void ExecuteCommandOnItem(ICommand command, int position)
{
    if (command == null)
        return;

    var item = this.Adapter.GetRawItem(position);
    if (item == null)
        return;

    if (!command.CanExecute(item))
        return;

    command.Execute(item);
}

Implementing this within our OnItemClick

public void OnItemClick(AdapterView parent, View view, int position, long id)
{
    MvxListView listView = parent as MvxListView;
    if (listView == null)
        return;

    var item = listView.Adapter.GetRawItem(position);

    if(item == null) 
        return;

    if (!listView.ItemClick.CanExecute(item))
        return;

    listView.ItemClick.Execute(item);

    // Write your code here for expanding the view
}

I'm not sure if this is the way to go, but it is one way to achieve what you're trying.

0
votes

The ItemClickCommand will only give you the ViewModel not the View. In order to do such a thing you will need to either create your own binding that returns the view on ItemClick, similar to the one that comes with MvvmCross. Or subscribe to the ItemClicked event on the ListView and handle stuff there.

The former would probably not be be the best idea as it will not be platform agnostic at all and you would have to set up the Command from the View anyways, which to me seems a bit silly.

So I would guess a simple subscription to the ItemClick event on MvxListView/ListView would do be able to do the job of returning the View.

Another approach could be to toggle the expansion through a property of the bound ViewModel of the view cell, which could toggle visibility with an animation or whatever you prefer.

0
votes

I tried out @Pilatus solution and it seemed to have worked with a little extra work. I did end up using your OnItemClick method after implementing AdapterView.IOnItemClickListener. The extra thing I had to do was set the _listView.OnItemClickListener = this; (this is the class that implemented the AdapterView.IOnItemClickListener). I was then able to use the View that was passed into that method and manipulate it.

Also, as an added note, the ICommand binding didn't get cancelled out. In my implementation, both events got triggered!