How do I make a thread safe call to a listview.
-
I get an Invalid Operation Exception error because the program is trying to make a cross-thread call to a listview object that was created by the main thread. The basic operation of the program is that items can be added, removed, modified,and cleared for the listview component on the panel. If I want, I can start a timer. Meanwhile a 'listener' sits in another thread waiting for the time to elapse. On this elapsed timer event, it enters the OnTimerDoThis() event-handler. Within the event-handler, on the foreach line, the 'Invalid Operation Exception' error occurs only after an item is added to the listview, or if an item exists already. I have put a comment at the end of the line -> '//ERROR HAPPENS HERE' so that using Find will take you to that line. The purpose of the foreach is to search the listview items and indicate if it matches to a string constant. I was able to create a delegate for a radio component and able to handle the same exception error, but need to do the same for the listview. Question is how do I get around the error? FYI. I am not using the background watcher. protected void OnTimerDoThis(Object source, ElapsedEventArgs e) { // immediatly disable timer after timeout interval reached DisableTimer(); MessageBox.Show("Inside OnTimerDoThis asnyc event\n\nTimer Disabled\n\n" + "Press OK to re-enable Timer"); foreach (ListViewItem item in lvData.Items) //ERROR HAPPENS HERE { //if (sWindowTitle.StartsWith(item.Text)) if (matchString.StartsWith(item.Text)) { MessageBox.Show("Inside match string and asnyc event\n\nTimer Disabled\n\n" + "Press OK to re-enable Timer"); } } EnableTimer(); } Regards....
-
I get an Invalid Operation Exception error because the program is trying to make a cross-thread call to a listview object that was created by the main thread. The basic operation of the program is that items can be added, removed, modified,and cleared for the listview component on the panel. If I want, I can start a timer. Meanwhile a 'listener' sits in another thread waiting for the time to elapse. On this elapsed timer event, it enters the OnTimerDoThis() event-handler. Within the event-handler, on the foreach line, the 'Invalid Operation Exception' error occurs only after an item is added to the listview, or if an item exists already. I have put a comment at the end of the line -> '//ERROR HAPPENS HERE' so that using Find will take you to that line. The purpose of the foreach is to search the listview items and indicate if it matches to a string constant. I was able to create a delegate for a radio component and able to handle the same exception error, but need to do the same for the listview. Question is how do I get around the error? FYI. I am not using the background watcher. protected void OnTimerDoThis(Object source, ElapsedEventArgs e) { // immediatly disable timer after timeout interval reached DisableTimer(); MessageBox.Show("Inside OnTimerDoThis asnyc event\n\nTimer Disabled\n\n" + "Press OK to re-enable Timer"); foreach (ListViewItem item in lvData.Items) //ERROR HAPPENS HERE { //if (sWindowTitle.StartsWith(item.Text)) if (matchString.StartsWith(item.Text)) { MessageBox.Show("Inside match string and asnyc event\n\nTimer Disabled\n\n" + "Press OK to re-enable Timer"); } } EnableTimer(); } Regards....
-
I am not sure I understood everything but ... aren't you trying to iterate through listview items with a thread while eventually modifying the same collection with another one (the main one) ?
Yes. The main thread allows the user to add, remove, modify, clear, the listview. I have a button the allows the user to Start of Stop the timer. If I start the timer, and the timer has elapsed, it will search the items in the listview for a match in the async thread event-handler OnTimerDoThis(). This is mainly for me to understand why the error occurs and how to handle the error. I plan on using something like this in the future with better functionality, but before going BIG, I need to understand the smaller stuff. If you want I can forward the file for your review thanks for the quick reply
-
Yes. The main thread allows the user to add, remove, modify, clear, the listview. I have a button the allows the user to Start of Stop the timer. If I start the timer, and the timer has elapsed, it will search the items in the listview for a match in the async thread event-handler OnTimerDoThis(). This is mainly for me to understand why the error occurs and how to handle the error. I plan on using something like this in the future with better functionality, but before going BIG, I need to understand the smaller stuff. If you want I can forward the file for your review thanks for the quick reply
cirkit1 wrote:
Yes.
I strongly urge you to read some material about multi-threading and synchronization. I recommend the book Advanced Windows by Richter. I have also seen people recommend a web site tutorial on threading but I don't know the URL. I am sure you can find it using google. I think there are articles here on CodeProject as well.
-
cirkit1 wrote:
Yes.
I strongly urge you to read some material about multi-threading and synchronization. I recommend the book Advanced Windows by Richter. I have also seen people recommend a web site tutorial on threading but I don't know the URL. I am sure you can find it using google. I think there are articles here on CodeProject as well.
-
cirkit1 wrote:
Yes.
I strongly urge you to read some material about multi-threading and synchronization. I recommend the book Advanced Windows by Richter. I have also seen people recommend a web site tutorial on threading but I don't know the URL. I am sure you can find it using google. I think there are articles here on CodeProject as well.
I have searched a multitude of sites and so far nothing specific to listview and my particular problem, hence my posting. There is a lot out there though, I agree. As an FYI, I was able to handle the same exception error regarding a radio control where I needed to change the boolean state of radio component from an async process, specifically when called from event-handler OnTimerDoThis(). I did this by following some examples for a textbox from MSDN. The following is portions of code to do this: // create a delegate within the class delegate void SetRadioCallback(bool Status); private void SetRadio(bool status) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.rdoTimerStatus.InvokeRequired) { // calling and creating thread are different SetRadioCallback r = new SetRadioCallback(SetRadio); this.Invoke(r, new object[] { status }); } else { this.rdoTimerStatus.Checked = status; } } // EnableTimer() is called from the main thread and async thread // at different times, never at the same time protected void EnableTimer() { m_Timer.Enabled = true; // call SetRadio to determine which thread is calling and update this.SetRadio(true); } Now, how do I do the same for a listview? I am not really changing anything in the listview. I just want it to search in the listview items for a match on the time elapsed event.
-
I have searched a multitude of sites and so far nothing specific to listview and my particular problem, hence my posting. There is a lot out there though, I agree. As an FYI, I was able to handle the same exception error regarding a radio control where I needed to change the boolean state of radio component from an async process, specifically when called from event-handler OnTimerDoThis(). I did this by following some examples for a textbox from MSDN. The following is portions of code to do this: // create a delegate within the class delegate void SetRadioCallback(bool Status); private void SetRadio(bool status) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.rdoTimerStatus.InvokeRequired) { // calling and creating thread are different SetRadioCallback r = new SetRadioCallback(SetRadio); this.Invoke(r, new object[] { status }); } else { this.rdoTimerStatus.Checked = status; } } // EnableTimer() is called from the main thread and async thread // at different times, never at the same time protected void EnableTimer() { m_Timer.Enabled = true; // call SetRadio to determine which thread is calling and update this.SetRadio(true); } Now, how do I do the same for a listview? I am not really changing anything in the listview. I just want it to search in the listview items for a match on the time elapsed event.
cirkit1 wrote:
I have searched a multitude of sites and so far nothing specific to listview and my particular problem
That's why I posted what I did. In my opinion you don't want to try to learn about mult threading issues by being "specific" to using a listview. You seem resistant to my suggestion so I am not going to argue with you. Have you found this MSDN Article[^]
-
I have searched a multitude of sites and so far nothing specific to listview and my particular problem, hence my posting. There is a lot out there though, I agree. As an FYI, I was able to handle the same exception error regarding a radio control where I needed to change the boolean state of radio component from an async process, specifically when called from event-handler OnTimerDoThis(). I did this by following some examples for a textbox from MSDN. The following is portions of code to do this: // create a delegate within the class delegate void SetRadioCallback(bool Status); private void SetRadio(bool status) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.rdoTimerStatus.InvokeRequired) { // calling and creating thread are different SetRadioCallback r = new SetRadioCallback(SetRadio); this.Invoke(r, new object[] { status }); } else { this.rdoTimerStatus.Checked = status; } } // EnableTimer() is called from the main thread and async thread // at different times, never at the same time protected void EnableTimer() { m_Timer.Enabled = true; // call SetRadio to determine which thread is calling and update this.SetRadio(true); } Now, how do I do the same for a listview? I am not really changing anything in the listview. I just want it to search in the listview items for a match on the time elapsed event.
Have a look at: http://msdn2.microsoft.com/en-us/library/system.collections.ienumerator(VS.80).aspx In particular: An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException And: http://www.yoda.arachsys.com/csharp/threads/winforms.shtml Regards
-
cirkit1 wrote:
I have searched a multitude of sites and so far nothing specific to listview and my particular problem
That's why I posted what I did. In my opinion you don't want to try to learn about mult threading issues by being "specific" to using a listview. You seem resistant to my suggestion so I am not going to argue with you. Have you found this MSDN Article[^]
-
I have searched a multitude of sites and so far nothing specific to listview and my particular problem, hence my posting. There is a lot out there though, I agree. As an FYI, I was able to handle the same exception error regarding a radio control where I needed to change the boolean state of radio component from an async process, specifically when called from event-handler OnTimerDoThis(). I did this by following some examples for a textbox from MSDN. The following is portions of code to do this: // create a delegate within the class delegate void SetRadioCallback(bool Status); private void SetRadio(bool status) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.rdoTimerStatus.InvokeRequired) { // calling and creating thread are different SetRadioCallback r = new SetRadioCallback(SetRadio); this.Invoke(r, new object[] { status }); } else { this.rdoTimerStatus.Checked = status; } } // EnableTimer() is called from the main thread and async thread // at different times, never at the same time protected void EnableTimer() { m_Timer.Enabled = true; // call SetRadio to determine which thread is calling and update this.SetRadio(true); } Now, how do I do the same for a listview? I am not really changing anything in the listview. I just want it to search in the listview items for a match on the time elapsed event.
Hi,
cirkit1 wrote:
I am not really changing anything in the listview.
whatever you want to do to a Control (set a property, get a property, call a method), you must do so from the thread that created the Control in the first place. With the exception of a few: Control.InvokeRequired, Control.Invoke(), etc. So yes, you need the same "if InvokeRequired Invoke self" construct even to read a ListView item. BTW: Now you may choose to do this for each and every single Control access, or you may move a higher-level method to the Control's thread of course, that would take more GUI time (i.e. freeze your GUI longer), but all-in-all be better performance wise. :)
Luc Pattyn [Forum Guidelines] [My Articles]
this months tips: - use PRE tags to preserve formatting when showing multi-line code snippets - before you ask a question here, search CodeProject, then Google