Hi
After reading hundreds of lines of text about threading and keeping everything thread safe I still do not get the following.
I have created on my main thread Items into a UltraListView, now at another time(not at creation) on another worker thread I want to update a subitem and or the text of the main column. So using a keyIndex linked to the MainColumn Item I use Dim intIndex as Integer = UltraListView1.Items.IndexOf(ItemKey) to return the required index if available. If a valid index is returned then I use Dim clmX as UltraListViewItem = UltraListView1.Items(intIndex) to make a reference to the object. When I need to set the Text property I use the Invoke as required on the clmX and pass it to the correct thread.
Now as I do not get a cross thread error when returning the IndexOf and no error when getting the clmX object is this method classed as thread safe?
Should I be using a Invoke to get the IndexOf or Invoking to get a UltraListViewItem for reference in the Dim?
-Paul
Hi Paul,
No Windows Forms controls are thread-safe. I am including the Infragistics controls as well as the inbox controls. I suppose there might be some other third-party controls out there that are, but if so, I am not aware of them.
It's hard to understand from your description what you are trying to do here. But you cannot refer to the control from another thread. There is no safe way to do that. So if you have a line of code like:
Dim intIndex as Integer = UltraListView1.Items.IndexOf(ItemKey)
And this code exists on the worker thread, that's a problem. There is no safe way to make that work, because you simply cannot reference a control that exists on the UI thread from a background thread safely.
FPSI said:Now as I do not get a cross thread error when returning the IndexOf and no error when getting the clmX object is this method classed as thread safe?
The fact that you are not getting an error is not indicative that this is a safe operation. In fact, one of the hallmarks of threading problems is that code like this often seems to work find and then causes an exception somewhere else in the code that is seemingly unrelated. This is why threading issues are do difficult to debug.
Hi Mike
Thank you for reply. I think this is why it gets so confusing, its wrong to do but nothing seems to go wrong.
I have substituted the Dim intIndex as Integer to :
Dim intIndex as Integer = GetUltraListViewIndexOf(UltraListView1,ItemKey)
Public Function GetUltraListViewIndexOf(ByVal UltraListView As Infragistics.Win.UltraWinListView.UltraListView, ByVal ItemKey As String) As Integer Dim intIndexOf As Integer = -1 If UltraListView.InvokeRequired Then intIndexOf = CInt(UltraListView.Invoke(New GetUltraListViewIndexOfInvoker(AddressOf GetUltraListViewIndexOf), UltraListView, ItemKey)) Else intIndexOf = UltraListView.Items.IndexOf(ItemKey) End If Return intIndexOf End Function
Dim clmX as UltraListViewItem = GetUltraListViewItem(UltraListView1,ItemIndex)
Public Function GetUltraListViewItem(ByVal UltraListView As Infragistics.Win.UltraWinListView.UltraListView, ByVal ItemIndex As Integer) As UltraListViewItem Dim clmXUltraListViewItem As UltraListViewItem = Nothing If UltraListView.InvokeRequired Then clmXUltraListViewItem = DirectCast(UltraListView.Invoke(New GetUltraListViewItemInvoker(AddressOf GetUltraListViewItem), UltraListView, ItemIndex), UltraListViewItem) Else clmXUltraListViewItem = UltraListView.Items(ItemIndex) End If Return clmXUltraListViewItem End Function
But I can see that you said 'There is no safe way to make that work' do you mean there is no way to do this on a worker thread at all? so even my new code will not work? I do not want to continue changing my code if I'm on the wrong path.
Hello,
I am just checking about the progress of this issue. Let me know If you need my further assistance on this issue?
Thank you for using Infragistics Components.
There are some, very limited circumstances in which you would use them. But in order to use them safely, you have to ensure that they are used all the time and there is absolutely no communications across the threads that it not properly marshaled.
The problem is that in many cases, you are not in control of the communication across the threads. For example, in your case, you are accessing properties of the ListView control (which exists on the UI thread) from your background thread. The problem is that these properties could be accessed at any time on the UI Thread. Even in the middle of operations which should otherwise be atomic. So, if your code on the UI thread happens to be adding item to the list (just as an example) while the code in your background thread is looping through those items, the loop will get out of synch and something is likely to blow up. Even if you are sure you are not adding or removing items at the time, it's possible that the user is in the process of moving the mouse over a list item and it's hottracking. So that item is changing even as you are looping through the list.
Thank you for explaining.
I'm now wondering whats the point of including InvokeRequired, Invoke and all the other methods if its best not to use them. Its like having a special button in your car but you best not use it because it can make strange things happen. What weird world we live in.
Well back to the drawing board. Thank you again for your time.
I'm still not really clear on what you need. But let's take the example of a SpellChecker. We have an UltraSpellChecked component which can put a red squiggly line under misspelled words in a TextBox control. If you have a really large textbox with a lot of text in it, the spelling errors take some time to show up, because the SpellChecker uses a background thread to check the spelling so as not to lock up the UI.
But the background thread can never reference the TextBox control. The component just passes in the text or words to be checked, because those are just strings and you can invoke those across the thread safely.
So maybe you could do something similar here where you keep a list of the values in your ListItems instead of passing the ListView itself. Of course, creating a copy of the list to pass into the background thread probably won't save you must in terms of performance. Unless you continuously maintain a cached list, you'd have to loop through the ListItems to build the list and this has to be done on the UI thread. But in theory, you only have to do this once and then you just keep the list in synch with the ListView when something changes.
Personally, I never use threading in Windows Forms. As I said, it's extremely complex. It's very easy for you to miss some case where a control is referencing something that is being accessed in some roundabout way on the other thread. Then your application will end up crashing, sporadically, at some seemingly random point that has nothing to do with the real issue and it's impossible to debug.
Its times like this where I wish I'd never started :-(
What I'm trying to do is like a spell checker or something of that nature where this process can be done on a background worker without to much interference to the user. I have a list of data values that sit in a listview, now depending on what the user selects (in my running program) the subItem values need to change. The information for the SubItems are returned from a database. I have to first make sure that one of the Data Values exists so I use the IndexOf to confirm that one exists. When found a lengthy calculation is done and the result is sent to the SubItem of the related data value(IndexOf). All this goes on while the user is doing other things.
So with this context am I on the wrong track?