Please help me spot the bug! I have read numerous posts here on this issue but I can't get mine to work. To me it looks like I'm doing it according to the other solutions but I'm missing something.
I have a survey implemented as a question with 3 possible answers using recyclerview where each row has a radio group with 3 radio buttons.
When scrolling the radio button looses its value and doesn't get set again in the onbind event.
public class MyQItem
{
public int Id;
public string Question;
public int Value;
public MyQItem(int id, string question)
{
Id = id;
Question = question;
}
}
internal class MyQFormAdapter : RecyclerView.Adapter
{
private MyQItem[] mDataSource;
public MyQFormAdapter(MyQItem[] mDataSource)
{
this.mDataSource = mDataSource;
}
public override int ItemCount => mDataSource.Length;
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
MyQViewHolder vh = holder as MyQViewHolder;
vh.QuestionId.Text = mDataSource[position].Id.ToString();
vh.Question.Text = mDataSource[position].Question;
vh.Button1.CheckedChange -= Button1_CheckedChange;
vh.Button2.CheckedChange -= Button2_CheckedChange;
vh.Button3.CheckedChange -= Button3_CheckedChange;
vh.Button1.Checked = mDataSource[position].Value == 1;
vh.Button2.Checked = mDataSource[position].Value == 2;
vh.Button3.Checked = mDataSource[position].Value == 3;
vh.Button1.Tag = position;
vh.Button2.Tag = position;
vh.Button3.Tag = position;
vh.Button1.CheckedChange += Button1_CheckedChange;
vh.Button2.CheckedChange += Button2_CheckedChange;
vh.Button3.CheckedChange += Button3_CheckedChange;
}
void Button1_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e) => SetChecked((RadioButton)sender, 1, e.IsChecked);
void Button2_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e) => SetChecked((RadioButton)sender, 2, e.IsChecked);
void Button3_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e) => SetChecked((RadioButton)sender, 3, e.IsChecked);
void SetChecked(RadioButton btn, int value, bool isChecked)
{
if (!isChecked)
return;
var position = (int)btn.Tag;
mDataSource[position].Value = value;
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.MyQItemLayout, parent, false);
MyQViewHolder vh = new MyQViewHolder(itemView);
return vh;
}
}
[Activity(Label = "MyQEditActivity")]
public class MyQEditActivity : Activity
{
MyQItem[] mDataSource = new MyQItem[] {
new MyQItem(1, "Lorem Ipsum"),
new MyQItem(2, "Lorem Ipsum"),
new MyQItem(3, "Lorem Ipsum"),
new MyQItem(4, "Lorem Ipsum"),
new MyQItem(5, "Lorem Ipsum"),
new MyQItem(6, "Lorem Ipsum"),
new MyQItem(7, "Lorem Ipsum"),
new MyQItem(8, "Lorem Ipsum"),
new MyQItem(9, "Lorem Ipsum"),
new MyQItem(10, "Lorem Ipsum"),
new MyQItem(11, "Lorem Ipsum"),
new MyQItem(12, "Lorem Ipsum"),
};
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.MyQEditLayout);
var recyclerView = FindViewById<RecyclerView>(Resource.Id.recyclerView);
recyclerView.SetLayoutManager(new LinearLayoutManager(this));
recyclerView.SetAdapter(new MyQFormAdapter(mDataSource));
}
}
public class MyQViewHolder : RecyclerView.ViewHolder
{
public TextView QuestionId { get; private set; }
public TextView Question { get; private set; }
public RadioButton Button1 { get; private set; }
public RadioButton Button2 { get; private set; }
public RadioButton Button3 { get; private set; }
public MyQViewHolder(View itemView) : base(itemView)
{
QuestionId = itemView.FindViewById<TextView>(Resource.Id.MyQuestionId);
Question = itemView.FindViewById<TextView>(Resource.Id.MyQuestion);
Button1 = itemView.FindViewById<RadioButton>(Resource.Id.noButton);
Button2 = itemView.FindViewById<RadioButton>(Resource.Id.someButton);
Button3 = itemView.FindViewById<RadioButton>(Resource.Id.yesButton);
}
}
You can add listeners to your RadioGroup and modify your adapter like this:
class MyQFormAdapter : RecyclerView.Adapter, RadioGroup.IOnCheckedChangeListener
{
private MyQItem[] mDataSource;
public MyQFormAdapter(MyQItem[] mDataSource)
{
this.mDataSource = mDataSource;
}
public override int ItemCount => mDataSource.Length;
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
MyQViewHolder vh = holder as MyQViewHolder;
// cancel the listener to prevent RadioGroup from displaying confusing key codes
vh.Group.SetOnCheckedChangeListener(null);
vh.Group.ClearCheck();
vh.Group.Tag = position;
switch (mDataSource[position].Value)
{
case 1:
vh.Group.Check(Resource.Id.noButton);
break;
case 2:
vh.Group.Check(Resource.Id.someButton);
break;
case 3:
vh.Group.Check(Resource.Id.yesButton);
break;
}
vh.QuestionId.Text = mDataSource[position].Id.ToString();
vh.Question.Text = mDataSource[position].Question;
vh.Group.SetOnCheckedChangeListener(this);
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.MyQItemLayout, parent,false);
MyQViewHolder vh = new MyQViewHolder(itemView);
return vh;
}
public class MyQViewHolder : RecyclerView.ViewHolder
{
public TextView QuestionId { get; private set; }
public TextView Question { get; private set; }
public RadioGroup Group { get; private set; }
public MyQViewHolder(View itemView) : base(itemView)
{
QuestionId = itemView.FindViewById<TextView>(Resource.Id.MyQuestionId);
Question = itemView.FindViewById<TextView>(Resource.Id.MyQuestion);
Group = itemView.FindViewById<RadioGroup>(Resource.Id.radiogroup);
}
}
public void OnCheckedChanged(RadioGroup @group, int checkedId)
{
switch (checkedId)
{
case Resource.Id.noButton:
mDataSource[(int) @group.Tag].Value = 1;
break;
case Resource.Id.someButton:
mDataSource[(int)@group.Tag].Value = 2;
break;
case Resource.Id.yesButton:
mDataSource[(int)@group.Tag].Value = 3;
break;
}
}
}