Threads and processing the dictionary

I’m missing something here, and not quite sure what it is.

Originally I had a thread that in the run phase was getting a list of files from a folder and passing them to a dictionary for processing by the UserInterfaceUpdate event, and it worked when I was processing just the filename.

But I’ve tried passing in several other pieces of information into the dictionary (size and date) and now I am only receiving the first file repeatedly

When I was just doing the filename I was getting each and every one of them, now that I am trying to pass more info, I am repeatedly passing the first one over and over.

I know it’s my application of using the Dictionary Object, I’m just not sure what I’m doing wrong.

When I was doing it with just the filename I was passing just "name":file.name but now I’m trying to pass a complete dictionary (htis is where I’m going wrong).

This is my “Run” event:

Var file As FolderItem
Var folder As FolderItem = searchFolder
Var fileCount As Integer = folder.Count
Var D As New Dictionary

For i As Integer = 0 To fileCount-1
  file = folder.ChildAt(i)
  If file <> Nil Then
    D.Value("name") = file.Name
    D.Value("date") = file.CreationDate
    D.Value("size") = file.Length
    Thread1.AddUserInterfaceUpdate(D)
  End If
Next

and this is my update event:

Var i As Integer
For Each entry As Dictionary In data
  i  = lb.RowCount
  lb.AddRow(i.ToString)
  lb.CellValueAt(lb.LastAddedRowIndex, hcFileName) = entry.Value("name").StringValue
  lb.CellValueAt(lb.LastAddedRowIndex, hcDate) = entry.Value("date").StringValue
  lb.CellValueAt(lb.LastAddedRowIndex, hcSize) = entry.Value("size").StringValue
  
  window1.Title=lb.RowCount.ToString
Next

I feel like I’m missing something pretty basic.

I no longer have the code, but when I was processing JUST the filename, I hadn’t declared a dictionary and I was simply passing in “file”:file.name so the code was more like (from memory):

For i As Integer = 0 To fileCount-1
  file = folder.ChildAt(i)
  If file <> Nil Then
    Thread1.AddUserInterfaceUpdate("file":file.name)
  End If
Next

and then in the update event I simply added it to the listbox, but now I want to process multiple items at once

I’m going to leave the question above for prosperity, but what I want to do is process a larger dictionary (larger than a pair) in one go. At the moment I’m only able to process it item by item and I think it’s simply my approach, but I can’t put my finger on it.

What works is if in the “Run” event I pass "value":something and then process that individually, but what I’d like to do is group several things into a dictionary and process it as a whole to the UI. Regarding the original question, I have solved it by doing the following:

Var file As FolderItem
Var folder As FolderItem = searchFolder
Var fileCount As Integer = folder.Count
Var D As New Dictionary

For i As Integer = 0 To fileCount-1
  file = folder.ChildAt(i)
  If file <> Nil Then
    Thread1.AddUserInterfaceUpdate("name":file.name)
    Thread1.AddUserInterfaceUpdate("date":file.CreationDate)
    Thread1.AddUserInterfaceUpdate("size":file.Length)
  End If
Next
rem now that we have all the files added, let's start hashing!!!!

and then

Var i As Integer
For Each entry As Dictionary In data
  i  = lbHashes.RowCount
  If entry.HasKey("name") Then 
    lb.AddRow(i.ToString)
    lb.CellValueAt(lb.LastAddedRowIndex, hcFileName) = entry.Value("name").StringValue
  End
  If entry.HasKey("date") Then lb.CellValueAt(lb.LastAddedRowIndex, hcDate) = entry.Value("date").StringValue
  if entry.HasKey("size") Then lb.CellValueAt(lb.LastAddedRowIndex, hcSize) = entry.Value("size").StringValue
  window1.Title=lb.RowCount.ToString
Next

edit: I just feel this way is wrong. I’m sure I can do it as a whole, I’m just missing it. any help appreciated. thanks

you are using the same key in a loop that make no sense.
the AddUserInterfaceUpdate should be fired once with all data for the ui.
the value at dictionary is Variant so you could also give a list with objects.
each class object could store your propertys Name,CreationDate,Length

[quote=497347:@Markus Rauch]you are using the same key in a loop that make no sense.
the AddUserInterfaceUpdate should be fired once with all data for the ui.[/quote]
I realise I’m wrong, but I was of the opinion it would be a new dictionary each time.

So if it’s not, then I should be passing in a uniquely new key value each pass?

i just edited my last post

AHHHHH lightbulb moment, I think I see what I’m doing wrong, I’ll go play :slight_smile: /thanks!

Yeah, I re-read my original post dozens of times, and I never picked that up, I’ll go experiment, thanks!!!

i hope it works, i use threads rare.

Yeah, I don’t really want to, but I’m hashing large files and it takes time and make the GUI crap.

I’m not sure what I’m missing. I want to add a new entry to a dictionary, perhaps a dictionary is wrong, but how would I add a “set” of things repeatedly at a processing end, and then pull them off a heap at the other end?

I’d like to be able to treat is like a listbox or array and add entries to it and pluck them off.

Any suggestions?

Just to quickly show where I now know my thinking was wrong, I thought that having the AddUserInterfaceUpdate BEFORE the next statement would queue them up at the recipient end. … hence I thought I could re-use those values… But now I’m thinking to just use unique keys (the file names?) and pluck them from the other end…

I’ll keep plugging away at it, thanks for the help

maybe can this help, it separates data and the view.
Lazy Loading Data with ListBox

I have this method for any thread:

[code]Sub UIupdate (action As integer, optional arg1 As variant, optional arg2 As Variant, optional arg3 As Variant, optional arg4 As Variant)

Var UIdict As new Dictionary

UIdict.Value(“action”) = action
UIdict.Value(“arg1”) = arg1
UIdict.Value(“arg2”) = arg2
UIdict.Value(“arg3”) = arg3
UIdict.Value(“arg4”) = arg4

me.AddUserInterfaceUpdate (UIdict)

End sub[/code]

This way, each request for UI work is wholly contained in a new dictionary that is passed to the event handler, thus:

[code]sub updateUI (t As taskClass, UIdata() As Dictionary

Var updateItem as new Dictionary

while (UIdata.LastRowIndex>-1)

updateItem = UIdata(0)
UIdata.RemoveRowAt (0)

select case updateItem.Value(“action”)

case 1 // Update the dock icon
updateIcon ()

case 2
etc etc - all the other cases

end select

wend

end sub[/code]

When updateUI is finally called, since there is an array of dictionaries, there could be one or more in that array. Each is a separate work item and is pulled off the array of dictionaries by the while, and its action key value is used to drive the select. Each is treated entirely before the next one is looked at. No chance of missing one.

The updateUI method is wired to the thread when the thread is created:

AddHandler mailThread.UserInterfaceUpdate, WeakAddressOf updateUI // Wire in the UI updater function for this thread

My method for updating the UI has 20 cases in its select; it’s called from all over the app by a number of different threads.

You need a new dictionary inside the For loop.

Var file As FolderItem
Var folder As FolderItem = searchFolder
Var fileCount As Integer = folder.Count
Var D As Dictionary

For i As Integer = 0 To fileCount-1
  file = folder.ChildAt(i)
  If file <> Nil Then
    D = New Dictionary
    D.Value("name") = file.Name
    D.Value("date") = file.CreationDate
    D.Value("size") = file.Length
    Thread1.AddUserInterfaceUpdate(D)
  End If
Next

Otherwise, you’re just replacing the same values over and over and the update event just grabs the most recent.

[quote=497355:@Markus Rauch]maybe can this help, it separates data and the view.
Lazy Loading Data with ListBox[/quote]
Well, I’d come to the forums tonight to ask almost this exact question. It’s not quite what I was going to ask but it works along the same lines.

I haven’t yet tried the sample project, I’m not at home, but the concept sounds very nice. I’m curious as to how “fluid” the feel of scrolling around the list box to random positions quickly. Not that this is a usual feature or requirement, it just has to “feel” right. I do like the sound of it.

Ill experiment with that. Thanks.

[quote=497486:@Tim Hare]You need a new dictionary inside the For loop.

Var file As FolderItem
Var folder As FolderItem = searchFolder
Var fileCount As Integer = folder.Count
Var D As Dictionary

For i As Integer = 0 To fileCount-1
  file = folder.ChildAt(i)
  If file <> Nil Then
    D = New Dictionary
    D.Value("name") = file.Name
    D.Value("date") = file.CreationDate
    D.Value("size") = file.Length
    Thread1.AddUserInterfaceUpdate(D)
  End If
Next

Otherwise, you’re just replacing the same values over and over and the update event just grabs the most recent.[/quote]

I haven’t tested this specific implementation yet as I did resolve this another way, but after reading everyone’s posts, I’m realising where my thinking was out and I highlighted the key part that I had been missing. I was thinking they would be queued up but yes, it’s the same dictionary. (Hey @Tim Streater I know you basically said the same thing, but in this example my code would be fixed by just moving the dictionary declaration. At least I think that would do it. I’ll test that when I get the chance).

I’m moving into the next stage now, and now have to work with multiple threads. But I’ll do some more reading first and then ask a new question once I can articulate and demonstrate it.

Thanks everyone. Much appreciated.

Yes, it should do. It depends how many threads (and threads doing different things) you expect to get. In my case it was several of each which is why I had to set it up to be expandable.