Categories
Development Powershell

Multithreaded DataGridView

Welcome to a bit different post than usuall from me, don’t worry – It’s still Powershell!

I’ve been building a new generation of GUI for my Powershell tools for a while now, trying to implement all I’ve learned and make it more dynamic and easy to update.
I build all my GUIs by hand, no Powershell Studio or anything like that, just me and ISE (Still haven’t dared to go over to VSC…).
I have played around with WPF but has again returned to WinForms because of how simple it is and because I have way more experience working with it.

I will add a tutorial, hopefully in the near future, on how to create your own GUIs for your Powershell scripts, to show you that it is much easier and most people think!

OK – So the issue I had.
I’m building a “module” for the new tool, this module is a log reader and fetching the logs can take quite a while so I obviously wanted it done in the background in another thread, so that the GUI thread wouldn’t freeze during the log collection.
Problem was that when the DataSource is set on the DataGridView (DGV) the whole GUI soon froze until I had to close the process.
The update to the DGV was done in the second thread with nothing else happening in the primary thread, but still the freeze/hang happend.
The job in the second thread did not have time to finish either if I added something else to it so it was not connected to the job finishing/closing.

A lot of hair was pulled, curse words said and caffeine consumption increased before I finally found my solution!

Found this blog post with an example of how to update a DGV from another thread.
Matthew’s solution was a bit convoluted for my taste so I began testing exactly what I needed and found that it was not much at all!

I use a function called Update-DataGridView which sets the DataSource and then also autosizes all the columns.

$DataGridViewObject.datasource = $DataSource

$DataGridViewObject.Columns | Foreach-Object {$_.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells}

The above lines was basically all the function did and how it did it before I changed it to be “multithread compliant”.

$DataGridViewObject.Invoke([Action]{
   $DataGridViewObject.datasource = $DataSource

   $columns = $DataGridViewObject.Columns
   foreach($column in $columns){
      $column.AutoSizeMode = [System.Windows.Forms.DataGridViewAutoSizeColumnMode]::AllCells
   }
})

Two things have changed; We wrap the code with .Invoke([Action]{}), and the autosizing of the columns is no longer done with a pipeline.

The .Invoke part solves our main issue but then the pipeline caused the application to hang again so we removed it.

I can’t explain, yet, why the pipeline in the second thread causes the application to hang but for now I’m just happy I found a solution!

If you can explain the pipeline problem, please share it in the comments!

As always, continue to learn and evolve your skills, see you in the next one!

Do you want to know more? Here is a list of tutorials to check next