Throw ObservableCollection exception

I have a Xamarin application that implements a search function in which results are grouped. So I used a Grouped Listview.

private async void SearchRecipient()
{
    IList<Recipient> recipients = null;

    if (!string.IsNullOrWhiteSpace(RecipientSearched))
    {   
        recipients = await _service.GetRecipients(RecipientSearched.ToLower());

        FilteredRecipients.Clear();
        _userGroupedList.Clear();
        _officeGroupedList.Clear();

        if (recipients != null)
        {
            foreach (var r in recipients)
            {
                // Some logic to populate collections
                _userGroupedList.Add(selectable);
                _officeGroupedList.Add(selectable);
            }

            if (_userGroupedList.Count > 0)
                FilteredRecipients.Add(_userGroupedList);
            if (_officeGroupedList.Count > 0)
                FilteredRecipients.Add(_officeGroupedList);
        }
    }
}

FilteredRecipientsis ObservableCollection, _userGroupedListand _officeGroupedList- List.

public SearchRecipientPageModel()
{
    FilteredRecipients = new ObservableCollection<GroupedRecipientModel>();
    _userGroupedList = new GroupedRecipientModel("User");
    _officeGroupedList = new GroupedRecipientModel("Office");
}

Job search and grouping. The problem occurs when I repeat the search a second time, and FilteredRecipients.Clear()throws the following exception:

System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index'

UPDATE Problems only occur when a result item is selected using the checkbox. I think this is due to my implementation of Checkbox Renderer, because I replaced Checkbox with a switch and it seems to work. I had some problems to make it work in TwoWay mode binding, but maybe I did not fix it correctly.

    public class CustomCheckBox : View
{
    public bool Checked
    {
        get => (bool)GetValue(CheckedProperty);
        set => SetValue(CheckedProperty, value);
    }

    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    public object CommandParameter
    {
        get => GetValue(CommandParameterProperty);
        set => SetValue(CommandParameterProperty, value);
    }

    public static readonly BindableProperty CommandParameterProperty =
                                BindableProperty.Create("CommandParameter", typeof(object), typeof(CustomCheckBox), default(object));

    public static readonly BindableProperty CheckedProperty =
                                BindableProperty.Create("Checked", typeof(bool), typeof(CustomCheckBox), default(bool), propertyChanged: OnChecked);

    public static readonly BindableProperty CommandProperty =
                BindableProperty.Create("Command", typeof(ICommand), typeof(CustomCheckBox), default(ICommand));


    private static void OnChecked(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is CustomCheckBox checkbox)
        {
            object parameter = checkbox.CommandParameter ?? newValue;

            if (checkbox.Command != null && checkbox.Command.CanExecute(parameter))
                checkbox.Command.Execute(parameter);
        }
    }
}

renderer

public class CustomCheckBoxRenderer : ViewRenderer<CustomCheckBox, CheckBox>
{
    protected override void OnElementChanged(ElementChangedEventArgs<CustomCheckBox> e)
    {
        base.OnElementChanged(e);
        if (Control == null && Element != null)
            SetNativeControl(new CheckBox());

        if (Control != null)
        {                
            Control.IsChecked = Element.Checked;
            Control.Checked += (s, r) => { Element.Checked = true; };
            Control.Unchecked += (s, r) => { Element.Checked = false; };
        }
    }

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (e.PropertyName == nameof(Element.Checked))
            Control.IsChecked = Element.Checked;
    }
}

, , Checked .

+4
2

clear()

FilteredRecipients = new ObservableCollection<YourModel>();

Edit

.

if (e.OldElement != null)
{
      Control.Checked -= (s, r) => { Element.Checked = true; };
      Control.Unchecked -= (s, r) => { Element.Checked = false; };
}

if (e.NewElement != null)
{
      Control.Checked += (s, r) => { Element.Checked = true; };
      Control.Unchecked += (s, r) => { Element.Checked = false; };
}
0

ObservableCollection, :

public class SafeObservableCollection<T> : ObservableCollection<T>
{
    /// <summary>
    /// Normal ObservableCollection fails if you are trying to clear ObservableCollection<ObservableCollection<T>> if there is data inside
    /// this is workaround till it won't be fixed in Xamarin Forms
    /// </summary>
    protected override void ClearItems()
    {
        while (this.Items.Any())
        {
            this.Items.RemoveAt(0);
        }
    }
}
0

Source: https://habr.com/ru/post/1689438/


All Articles