Search code examples
c#xamarincollectionsobservablecollectionindexoutofrangeexception

Adding elements to ObservableCollection causes exception Index was out of range


I have a code that allows the user pick a file, adds some info about it to an observable collection and shows the upload progress, when finished, it binds the image to an Image view. It works properly at once but if you repeat the process, an exception is threw:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
  at at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.43(intptr,intptr)
  at at (wrapper native-to-managed) Android.Runtime.DynamicMethodNameCounter.43(intptr,intptr)

Code that inserts new element and get its index

switch(x){

 // some code...

    case 6:

        // .... some code 


            _ = Task.Run(async () => {
            try
            {
                int i = default;

            Msg newmsg2 = new Msg() { UploadProgress = 0.0, UploadProgressVisibility = true, IsImageSend = true, ImageSend = "@drawable/icon_default" };

            valuesLock.EnterWriteLock();
            try
            {
                // THE ISSUE IS RELATED WITH THIS WORK
                Device.BeginInvokeOnMainThread(() => ListaMsg.Add(newmsg2));
            }
            finally
            {
                valuesLock.ExitWriteLock();
                valuesLock.EnterReadLock();
                try
                {
                    // THE ISSUE IS RELATED WITH THIS WORK

                    i = ListaMsg.IndexOf(newmsg2); 

                    // Some data can be added while the progress is being updated, I need to get the index of this exactly Item, can't get it with Count-1

                }
                finally
                {
                    valuesLock.ExitReadLock();
                    Resultado a = await Task.Run(()=>UploadFile(filename, i));
                    if (a.status == "ok")
                    {
                        valuesLock.EnterWriteLock();
                        try
                        {
                            Device.BeginInvokeOnMainThread(() =>
                            {
                                MyList[i].msg = "Image was sent";
                                MyList[i].status = true;
                                MyList[i].ImageSend = "mydomain/assets/libs/thumb.php?h=150&w=150&img=" + a.msg;
                            });
                        }
                        finally
                        {
                            valuesLock.ExitWriteLock();
                            SendMsg(6, a.msg, i);
                        }
                    }
                    else
                    {
                        valuesLock.EnterWriteLock();
                        try
                        {
                            Device.BeginInvokeOnMainThread(() =>
                            {
                                MyList[i].ImageSend = "@drawable/icon_default";
                                MyList[i].icon = "\uf057";
                                MyList[i].IconColor = Xamarin.Forms.Color.Red;
                            });
                        }
                        finally { valuesLock.ExitWriteLock(); }
                    }
                }
            }
        }
        catch (Exception e)
        {
            ...
        }
    });
break;
}

UPLOAD METHOD

public async Task<Resultado> UploadFile(string url, string filepath)
{
  //some code

  webclient.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);

  //some code
}

And finnaly the ProgressChanged callback:

private void UploadProgressCallback(object sender, UploadProgressChangedEventArgs e, int idreference)
{
    double temp = ((double)e.BytesSent) / filesize;
    Device.BeginInvokeOnMainThread(() => {
        valuesLock.EnterWriteLock();
        try
        {
            // THE EXCEPTION IS BEING THREW AT LINE BELOW, idreference value is -1 and not the correct index
            MyList[idreference].UploadProgress = temp;
        }
        finally { valuesLock.ExitWriteLock(); }
    });
}

Why this works only at once? Did I miss or did something wrong?


Solution

  • The root of problem was the part that contains IndexOf() method. It was executing before the ancedent execution on Main Thread and index was always -1. Fixed by changing:

    Device.BeginInvokeOnMainThread(() => ... );
    

    by

    await Device.InvokeOnMainThreadAsync(() => { ... } );