Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monodroid - Handling events on child Views of reused ListView rows

Android's ListView reuses rows that have been scrolled out of view. But, that seems to be a problem when handling events on a row's child Views in C#.

An accepted way of adding event handlers in Java is to explicitly set a handler like so:

ImageView img = (ImageView) row.findViewById(R.id.pic);
img.setOnClickListener(new View.OnClickListener() {  
    public void onClick(View v) {
        System.out.println(position);
    }  
});

Documents on Xamarin's site encourage developers to use C#'s add event listener pattern which doesn't play nice with reused rows:

ImageView img = row.FindViewById<ImageView> (Resource.Id.pic);
img.Click += (sender, e) => {
    Console.WriteLine(position);
};

The Java pattern above which sets an event handler is well suited for row reuse while the C# pattern beneath it which adds an event handler causes handlers to pile up on child Views of the reused rows.

The code below shows my GetView method from a custom BaseAdapter I wrote.

public override Android.Views.View GetView (int position,
                                            View convertView, ViewGroup parent)
{
    View row = convertView;

    //TODO: solve event listener bug. (reused rows retain events).
    if (row == null) {
        row = LayoutInflater.From (userListContext)
                .Inflate (Resource.Layout.UserListUser, null, false);
    }

    ImageView profilePic = row.FindViewById<ImageView> (Resource.Id.profilePic);

    //if(profilePic.Clickable) { /** kill click handlers? **/ }
    profilePic.Click += async (object sender, EventArgs e) => {
        Bundle extras = new Bundle();
        extras.PutString("id", UserList[position].id);

        Intent intent = new Intent(userListContext, typeof(ProfileActivity));
        intent.PutExtras(extras);
        postListContext.StartActivity(intent);
    };

    return row;
}

The problem is, when a row is reused, the profilePic view still has the original "click" handler attached.

Is there a way to (a) wipe out profilePic.Click or (b) use the Android's profilePic.SetOnClickListener Java pattern with anonymous functions?

Or, is there a better pattern to use where the "click" handler can still access the proper value of position?

like image 973
MicronXD Avatar asked Sep 29 '22 18:09

MicronXD


1 Answers

Or, is there a better pattern to use where the "click" handler can still access the proper value of position?

Use setTag/getTag method to get right position of clicked row inside Click method of ImageView click listener:

profilePic.SetTag(Resource.Id.profilePic, position);
profilePic.Click += async (object sender, EventArgs e) => {
        int clickedPos = (int)(((Button)sender).GetTag (Resource.Id.profilePic));
        Bundle extras = new Bundle();
        extras.PutString("id", UserList[clickedPos].id);
        ......
};
like image 86
ρяσѕρєя K Avatar answered Oct 03 '22 07:10

ρяσѕρєя K