Click here to Skip to main content
15,884,790 members
Please Sign up or sign in to vote.
4.40/5 (4 votes)
See more:
C#
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.
Posted

1 solution

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:
C#
ReportProgress(int);
ReportProgress(int, object);


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.

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


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.
 
Share this answer
 
v2
Comments
vasanthkumarmk 19-Aug-12 0:20am    
Ok thanks, i can it.
vasanthkumarmk 19-Aug-12 0:39am    
Thanks a lot, its working. But

Can you explain about these two signatures.
ReportProgress(int);
ReportProgress(int, object);

Where i can declare in my program.
Martijn Kok 19-Aug-12 10:26am    
If you look into the Visual Studio help for the BackgroundWorker.ReportProgress (or goto http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.reportprogress.aspx) you will see that there are two versions of the ReportProgress method.

You can use them based on the parameters you will supply. In your code you are using them both. If you only supply 1 parameter as an int (like in backgroundWorker1.ReportProgress(i * 100 / count)) then you are using the ReportProgress(int). If you read the help documentation you will see this one only can be used to report te progress.

When you supply 2 parameters (of which the first must be an int and the second can be any kind of object) you will use the ReportProgress(int,object). In the code this is the backgroundWorker1.ReportProgress(i * 100 / count, j). In this example the 2nd parameter is also an int, but it could be anything. In the helpdocumentation you will see that this parameter represents the UserState.

Having 2 or more signatures of the same method is called method overloading. You can use it in your own code too. For instance look at this page http://csharp.net-tutorials.com/classes/method-overloading/
vasanthkumarmk 22-Aug-12 5:10am    
Dear Sir,
I need to set Seconds for play items one by one from the list view. so I have set time using single text box. Code as below for set timing for selected list view items.
listView_playlist.SelectedItems[0].Tag = txtbox_timertime.Text;
txtbox_timertime.Text = "";
txtbox_timertime.Text =
listView_playlist.SelectedItems[0].Tag.ToString();
string a = listView_playlist.SelectedItems[0].Tag.ToString();
listView_playlist.SelectedItems[0].SubItems.Add(a);
MessageBox.Show("File Name of " + listView_playlist.Selected


i am getting timing from text box (named as txtbox_timertime.Text) and i make some alteration of what you code gave me. Just instead sleep i am using the textbox time. As below shows for your code include my alteration:
try
{
int count = (int)e.Argument;
int sum = 0;


for (int i = 0, j = 0; i < listView_playlist.Items.Count && j < listView_playlist.Items.Count; j++)
{
backgroundWorker1.ReportProgress(i * 100 / count, j);
int time = Convert.ToInt32(txtbox_timertime.Text);
Thread.Sleep(time * 1000);

if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
break;
}

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

e.Result = sum;
}
catch { }


What my problem is the Seconds not works proper timing. If we give 25 Seconds it will works for 2 seconds only.

So What changes i have do for recertify this solution

Awaiting your reply.

Regards
Vasanth
Martijn Kok 22-Aug-12 5:32am    
Hi Vasanth,

I'll look into it in about a few hours (currently working). You should also try to make this a new question. This will give other experts a chance to look at the problem too. All the experts together will definitly know more than I alone, and they will see the new question, but I doubt they will see this comment.

My first approach to this new problem would be to check which value is actually in the time int. Either place a breakpoint or insert a Console.WriteLine(time.ToString()); after the 'int time = ...' line. Check the output view of Visual Studio. Does it show 25 seconds or 2 seconds.

I would expect 2 seconds. So the problem is not the thread by the value in txtbox_timertime.Text.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900