0

I'm using a Datagridview inside a windows form to display some data. The data is loaded in the background after pressing a button. This works fine when I press the button for the first time.

But I need to be able, to do this again and again without closing the form. No matter what I try, after pressing ok a second time, my datagridview turns into white ground with big red x across it. I would like to empty/reset everything.

Here is a cut down version of my code:

Add-Type -AssemblyName System.Windows.Forms 

$sync = [Hashtable]::Synchronized(@{})

$backgroundTask = {
  $task1 = [PowerShell]::Create().AddScript({
        #here I would like to clear all data from a previous execution. But nothing worked.
        $softwareQuery = Get-WMIObject -ComputerName localhost  -Class Win32_Product | Select Name
        $softwareList = New-Object System.collections.ArrayList
        $softwareList.AddRange($softwareQuery)
        $sync.softwareTable.DataSource = $softwareList

  })
  $runspace = [RunspaceFactory]::CreateRunspace()
  $runspace.ApartmentState = "STA"
  $runspace.ThreadOptions = "ReuseThread"
  $runspace.Open()
  $runspace.SessionStateProxy.SetVariable("sync", $sync)
  $task1.Runspace = $runspace
  $task1.BeginInvoke()
}



$mainForm = New-Object system.Windows.Forms.Form
$mainForm.Size = New-Object System.Drawing.Size(900,600)

$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(280,5)
$okButton.Size = New-Object System.Drawing.Size(75,20)
$okButton.Text = "OK"
$okButton.Add_Click($backgroundTask) ;
$mainForm.Controls.Add($okButton)

$softwareTable = New-Object System.Windows.Forms.DataGridView -Property @{
    Location=New-Object System.Drawing.Point(5,30)
    Size=New-Object System.Drawing.Size(840,360)
    ColumnHeadersVisible = $true     
}
$mainForm.Controls.Add($softwareTable)
$sync.softwareTable = $softwareTable

$mainForm.ShowDialog()

2 Answers2

0

I think one of the issues might be that you are trying to update a form control from a different thread. I am not an expert but in my experience that could go wrong in some ways.

To clear the datagridview, have you tried to set the Datasource property of the datagridview to $null before assigning it a new value? That is how I usually get mine done.

Sid
  • 2,586
  • 1
  • 11
  • 22
0

I see two issues, the first that you need to clear the datasource, and the second is that you're trying to call the action too soon after clicking the button and opening the runspace. Put a simple start-sleep in there and that issue should be resolved. I'd recommend playing with the time that you sleep it for to get the fastest execution. The second is also an easy fix, just clear the datasource before you declare what task1 is. This worked for me.

$backgroundTask = {
$sync.softwareTable.DataSource = $null
  $task1 = [PowerShell]::Create().AddScript({

        #here I would like to clear all data from a previous execution. But nothing worked.
        $softwareQuery = Get-WMIObject -ComputerName virinfpshd001w  -Class Win32_Product | Select Name
        $softwareList = New-Object System.collections.ArrayList
        $softwareList.AddRange($softwareQuery)
        $sync.softwareTable.DataSource = $softwareList

  })
  $runspace = [RunspaceFactory]::CreateRunspace()
  $runspace.ApartmentState = "STA"
  $runspace.ThreadOptions = "ReuseThread"
  $runspace.Open()
  $runspace.SessionStateProxy.SetVariable("sync", $sync)
  $task1.Runspace = $runspace
  $handle = $task1.BeginInvoke()
  Start-Sleep -seconds 5
}
Nick
  • 1,178
  • 3
  • 24
  • 36
  • Thanks a lot! So the problem was, that i have tried to set .DataSource = $null inside $task1? But can you explain, why I can set .DataSource = $softwareList inside $task1, but can't set it = $null inside $task1? Also, why did you change it to $handle = $task1.BeginInvoke()? – jemandanders Jan 25 '18 at 19:16
  • Sorry, I meant to remove handle before I posted, that's just something I use for my xaml/PS apps. The reason it can't be in task1 is that task1 is run in the separate runspace. When you click the button, it needs to clear the datagrid in the same runspace that it was previously using. By clearing the source outside of the task, you're starting over allowing the next button click to claim the datasource. – Nick Jan 25 '18 at 19:21
  • Ok, thanks again. And why sleep at this point? The sleep happens after all data has been passed to the datagridview. Or is it just to limit the time until the button can be pressed again? – jemandanders Jan 25 '18 at 22:34
  • I've had many issues with clicking the button, and the app freezing or crashing, especially when calling a fast function. The sleep function gives the pause needed to eliminate the null value error. – Nick Jan 25 '18 at 22:37