Monodroid - 处理子事件上的事件重用的ListView行的视图

Mic*_*nXD 5 c# mono android xamarin.android xamarin

Android的ListView重用已滚出视图的行.但是,当在C#中处理行的子视图上的事件时,这似乎是一个问题.

在Java中添加事件处理程序的一种可接受的方法是显式设置一个像这样的处理程序:

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

Xamarin网站上的文档鼓励开发人员使用C#的add事件监听器模式,这种模式对重用行不起作用:

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

上面设置事件处理程序的Java模式非常适合于行重用,而在其下面添加事件处理程序的C#模式会导致处理程序堆积在重用行的子视图上.

下面的代码显示GetView了我编写的自定义BaseAdapter中的方法.

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;
}
Run Code Online (Sandbox Code Playgroud)

问题是,当重用一行时,profilePic视图仍然附加了原始的"click"处理程序.

有没有办法(a)消除profilePic.Click或(b)使用Android的profilePic.SetOnClickListenerJava模式与匿名函数?

或者,有没有更好的模式使用"点击"处理程序仍然可以访问正确的值position

ρяσ*_*я K 3

或者,是否有更好的模式可以使用,“点击”处理程序仍然可以访问正确的位置值?

使用setTag/getTag方法在单击侦听器的 Click 方法中获取单击行的正确位置ImageView

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);
        ......
};
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的方法,但请记住,这会添加一个新的匿名事件处理程序,该处理程序无法在每次重用该行时取消注册。将委托逻辑转移到一个单独的方法中并取消注册,然后在每次调用“GetView”时重新注册它。 (2认同)