将元素添加到ObservableCollection导致异常索引超出范围。

3

我有一段代码,允许用户选择一个文件,将一些信息添加到可观测集合中,并显示上传进度。当完成后,它将图像绑定到 ImageView 上,它一次可以正常工作,但是如果重复这个过程,就会抛出异常:

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)

插入新元素并获取其索引的代码

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;
}

上传方法

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

  webclient.UploadProgressChanged += new UploadProgressChangedEventHandler(UploadProgressCallback);

  //some code
}

最后讲一下ProgressChanged回调函数:

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(); }
    });
}

为什么只有第一次有效?我错过了什么或做错了什么吗?

注意:Xamarin不是我的领域,但我了解线程。如果主线程在将项目添加到列表之前调用IndexOf会发生什么?您正在调用BeginInvokeOnMainThread,听起来它不会等待完成。 - ProgrammingLlama
如果我在调用IndexOf之前,由于List中不包含所需元素,它将不会得到任何索引。我认为这里需要使用BeginInvokeOnMainThread,因为添加新项将更新UI。 - Éder Rocha
请再次阅读我所说的话。 - ProgrammingLlama
@John 嗯,我会尝试做一些等待祖先工作的事情,并让您知道!谢谢。 - Éder Rocha
1
很高兴听到你解决了它。我建议添加一个答案(你可以回答自己的问题),这样将来遇到相同问题的人就可以从中学习。 :) - ProgrammingLlama
显示剩余5条评论
1个回答

6
问题的根源在于包含IndexOf()方法的那一部分。它在主线程之前执行,因此索引始终为-1。通过更改如下内容得到修复:
Device.BeginInvokeOnMainThread(() => ... );

by

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

3
你能否标记这个答案,以便更多遇到相同问题的人能够受益 :)。 - nevermore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接