错误:跨线程操作无效:从不是其创建线程的线程访问控件"listView1". [英] ERROR : Cross-thread operation not valid: Control 'listView1' accessed from a thread other than the thread it was created on.

查看:80
本文介绍了错误:跨线程操作无效:从不是其创建线程的线程访问控件"listView1".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
       {
           int count = (int)e.Argument;
           int sum = 0;
         

           for (int i = 0, j = 0; i < listView1.Items.Count && j < listView1.Items.Count; j++)
           {
               if (j != 0)
               {
                   listView1.Items[j - 1].Selected = false; //<big>ERRORR</big>
               }

               listView1.Items[j].Selected = true; //<big>ERROR</big>               
               Thread.Sleep(2000);
               if (backgroundWorker1.CancellationPending)
               {
                   e.Cancel = true;
                   break;
               }


               sum += i;
               backgroundWorker1.ReportProgress(i*100/count);
               Thread.Sleep(2000);
           }

           e.Result = sum;
       }




任何人都请纠正此错误.




Any one Please Rectify this Error.

推荐答案

此错误的原因是backgroundworker在其自己的线程中运行.您的UI(包括listView1)正在另一个(可能是应用程序的主线程)中运行.允许从另一个线程中的对象检索属性,但不允许更改它们.

解决方案是先进入UI线程,然后更改所选项目.在Windows窗体中使用线程时,可以通过调用Invoke语句来完成.但是,如果您使用BackgroundWorker,则有一个更简单的选择(尽管在更复杂的情况下,您可能更喜欢使用Invoke).

ProgressChanged事件在UI线程中处理.这是您要更新listView1的地方. ReportProgress具有两个签名:
The cause of this error is that the backgroundworker runs in its own thread. Your UI including the listView1 is running in another (probably the main thread of your application). retrieving properties from object in another thread is allowed, but changing them is not.

The solution is to get into the UI thread first and then change the selected item. When using threads in a Windows form, this can be done by calling the Invoke statement. But there is an easier alternative if you are using the BackgroundWorker (although in more complex situations one might prefer to use the Invoke).

The ProgressChanged event is handled in the UI thread. This is were you want to update the listView1. The ReportProgress has two signatures:
ReportProgress(int);
ReportProgress(int, object);



后者具有一个额外的参数,您可以使用该参数发送任何对象(包括自定义类).您可以使用此值将值j传递到UI线程. ProgressChangedEventArgs.UserState将包含j的值.



The latter has a extra parameter which you can use to send any object (including custom classes). You can uses this to pass the value j to the UI thread. The ProgressChangedEventArgs.UserState will contain the value of j.

private void StartButton_Click(object sender, EventArgs e)
{
    //Some code

    //Worker1.RunAsync(count);  //Old way to start - in your old call you already pass a variable, I assume its called count.
    //Determine current selected
    int currentSelected = 0;
    for (i = 0; i < ListView1.Items.Count; i++)
    {
        if (ListView1.Items[i].Selected == true)
        {
            currentSelected = i;
            break;
        }
    }
    // I used a Tuple type, this is a way to pass two (or more) variable in one object
    Worker1.RunAsync(new Tuple<int, int>(count, currentSelected));
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    int count = 0; //Changed this
    int sum = 0;
    int currentSelected = 0;
    if (e.Argument is Tuple<int, int>)
    {
        count = (e.Argument as Tuple<int, int>).Item1;
        currentSelected = (e.Argument as Tuple<int, int>).Item2;
    }
    bool isCurrentSet = false;


    for (int i = 0, j = 0; i < listView1.Items.Count && j < listView1.Items.Count; j++)
    {
        if (!isCurrentSet)
        {
           j = currentSelected;
           isCurrentSet = true; // Make sure j is only changed in the first call.
        }

        backgroundWorker1.ReportProgress(i * 100 / count, j);
        Thread.Sleep(2000);
        if (backgroundWorker1.CancellationPending)
        {
            e.Cancel = true;
            break;
        }


        sum += i;
        backgroundWorker1.ReportProgress(i * 100 / count);
        Thread.Sleep(2000);
    }

    e.Result = sum;
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //Report the progress, this might be some different code
    progressBar1.Value = e.ProgressPercentage;

    //Update the listView1, only if the index of the selected item is supplied
    if (e.UserState != null)
    {
        int j = (int)e.UserState;

        if (j != 0)
        {
            listView1.Items[j - 1].Selected = false;
        }

        listView1.Items[j].Selected = true;
    }
}



这可能会解决您遇到的错误.

您可能还需要检查进度报告.因为i值没有增加,所以进度保持在0.



This will probably solve the error you encountered.

You might need to check the progress reporting too. The progress remained at 0 because the i value wasn''t increased.


这篇关于错误:跨线程操作无效:从不是其创建线程的线程访问控件"listView1".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆