derhoeppi
Goto Top

Powershell Datagridview Zeilen bearbeiten

Hallo Leute,

ich habe eine Frage. Ich habe mir eine GUI erstellt, die ein Datagridview, ein paar Buttons und Textboxen enthält. Das Datagridview (ReadOnly Mode - kein direktes editieren möglich) hat als Datenquelle eine Datatable. Nun füge ich dem Datagridview über die Textboxen Werte hinzu. Anschließend möchte ich die Werte einer Zeile des Datagridviews bearbeiten und übernehme die Zeile in die entsprechenden Textboxen. Bis hierhin habe ich kein Problem - funktioniert 1A. Die geänderten Werte möchte ich nun im Datagridview in der entsprechenden Zeile aktualisiert haben. Und genau an diesem Punkt stehe ich auf dem Schlauch. Wenn ich mir den Datensatz im Datagridview über die Where-Methode filter, schaffe ich leider nicht das Zurückschrieben.

Als Basis habe ich folgenden Code
function Show-DatagridviewExampleDatatable_psf {

	#----------------------------------------------
	#region Import the Assemblies
	#----------------------------------------------
	[void][reflection.assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')  
	[void][reflection.assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')  
	#endregion Import Assemblies

	#----------------------------------------------
	#region Generated Form Objects
	#----------------------------------------------
	[System.Windows.Forms.Application]::EnableVisualStyles()
	$form1 = New-Object 'System.Windows.Forms.Form'  
	$buttonEdit = New-Object 'System.Windows.Forms.Button'  
	$buttonAdd = New-Object 'System.Windows.Forms.Button'  
	$labelValue2 = New-Object 'System.Windows.Forms.Label'  
	$labelValue3 = New-Object 'System.Windows.Forms.Label'  
	$labelValue1 = New-Object 'System.Windows.Forms.Label'  
	$textboxValue2 = New-Object 'System.Windows.Forms.TextBox'  
	$textboxValue3 = New-Object 'System.Windows.Forms.TextBox'  
	$textboxValue1 = New-Object 'System.Windows.Forms.TextBox'  
	$datagridviewProjectUser = New-Object 'System.Windows.Forms.DataGridView'  
	$buttonClose = New-Object 'System.Windows.Forms.Button'  
	$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'  
	#endregion Generated Form Objects

	#----------------------------------------------
	# User Generated Script
	#----------------------------------------------
	#Create datatable as datasource for datagridview
	$dtValues = New-Object System.Data.DataTable
	$dtValues.Columns.Add('Value1', [string])  
	$dtValues.Columns.Add('Value2', [string])  
	$dtValues.Columns.Add('Value3', [string])  
	$datagridviewProjectUser.DataSource = $dtValues
	
	$form1_Load={
		#TODO: Initialize Form Controls here
		
	}
	
	$buttonEdit_Click={
		#TODO: Place custom script here
		IF ($buttonEdit.Text -eq "Edit")  
		{
			$textboxValue1.Text = $datagridviewProjectUser.SelectedRows.Cells.Value
			$textboxValue2.Text = $datagridviewProjectUser.SelectedRows.Cells[1].Value
			$textboxValue3.Text = $datagridviewProjectUser.SelectedRows.Cells[2].Value
			$buttonAdd.Text = "Abort"  
			$buttonEdit.Text = "Save"  
		}
		ELSE
		{
			$buttonAdd.Text = "Add"  
			$buttonEdit.Text = "Edit"  
		}
	}
	
	$buttonAdd_Click={
		#TODO: Place custom script here
		IF ($buttonAdd.Text -eq "Add")  
		{
			$ValuesAdd = $dtValues.NewRow()
			$ValuesAdd['Value1'] = $textboxValue1.Text  
			$ValuesAdd['Value2'] = $textboxValue2.Text  
			$ValuesAdd['Value3'] = $textboxValue3.Text  
			$dtValues.Rows.Add($ValuesAdd)
			$textboxValue1.Text = ""  
			$textboxValue2.Text = ""  
			$textboxValue3.Text = ""  
		}
		ELSE
		{
			$textboxValue1.Text = ""  
			$textboxValue2.Text = ""  
			$textboxValue3.Text = ""  
			$buttonAdd.Text = "Add"  
			$buttonEdit.Text = "Edit"  
		}
	}
	
	# --End User Generated Script--
	#----------------------------------------------
	#region Generated Events
	#----------------------------------------------
	
	$Form_StateCorrection_Load=
	{
		#Correct the initial state of the form to prevent the .Net maximized form issue
		$form1.WindowState = $InitialFormWindowState
	}
	
	$Form_Cleanup_FormClosed=
	{
		#Remove all event handlers from the controls
		try
		{
			$buttonEdit.remove_Click($buttonEdit_Click)
			$buttonAdd.remove_Click($buttonAdd_Click)
			$form1.remove_Load($form1_Load)
			$form1.remove_Load($Form_StateCorrection_Load)
			$form1.remove_FormClosed($Form_Cleanup_FormClosed)
		}
		catch { Out-Null <# Prevent PSScriptAnalyzer warning #> }
	}
	#endregion Generated Events

	#----------------------------------------------
	#region Generated Form Code
	#----------------------------------------------
	$form1.SuspendLayout()
	#
	# form1
	#
	$form1.Controls.Add($buttonEdit)
	$form1.Controls.Add($buttonAdd)
	$form1.Controls.Add($labelValue2)
	$form1.Controls.Add($labelValue3)
	$form1.Controls.Add($labelValue1)
	$form1.Controls.Add($textboxValue2)
	$form1.Controls.Add($textboxValue3)
	$form1.Controls.Add($textboxValue1)
	$form1.Controls.Add($datagridviewProjectUser)
	$form1.Controls.Add($buttonClose)
	$form1.AutoScaleDimensions = '6, 13'  
	$form1.AutoScaleMode = 'Font'  
	$form1.ClientSize = '606, 261'  
	$form1.MaximizeBox = $False
	$form1.MinimizeBox = $False
	$form1.Name = 'form1'  
	$form1.ShowIcon = $False
	$form1.Text = 'Form'  
	$form1.add_Load($form1_Load)
	#
	# buttonEdit
	#
	$buttonEdit.Anchor = 'Bottom, Right'  
	$buttonEdit.Location = '385, 226'  
	$buttonEdit.Name = 'buttonEdit'  
	$buttonEdit.Size = '66, 23'  
	$buttonEdit.TabIndex = 25
	$buttonEdit.Text = 'Edit'  
	$buttonEdit.UseCompatibleTextRendering = $True
	$buttonEdit.UseVisualStyleBackColor = $True
	$buttonEdit.add_Click($buttonEdit_Click)
	#
	# buttonAdd
	#
	$buttonAdd.Anchor = 'Bottom, Right'  
	$buttonAdd.Location = '457, 226'  
	$buttonAdd.Name = 'buttonAdd'  
	$buttonAdd.Size = '66, 23'  
	$buttonAdd.TabIndex = 24
	$buttonAdd.Text = 'Add'  
	$buttonAdd.UseCompatibleTextRendering = $True
	$buttonAdd.UseVisualStyleBackColor = $True
	$buttonAdd.add_Click($buttonAdd_Click)
	#
	# labelValue2
	#
	$labelValue2.AutoSize = $True
	$labelValue2.Location = '464, 69'  
	$labelValue2.Name = 'labelValue2'  
	$labelValue2.Size = '40, 17'  
	$labelValue2.TabIndex = 21
	$labelValue2.Text = 'Value2'  
	$labelValue2.UseCompatibleTextRendering = $True
	#
	# labelValue3
	#
	$labelValue3.AutoSize = $True
	$labelValue3.Location = '463, 115'  
	$labelValue3.Name = 'labelValue3'  
	$labelValue3.Size = '40, 17'  
	$labelValue3.TabIndex = 20
	$labelValue3.Text = 'Value3'  
	$labelValue3.UseCompatibleTextRendering = $True
	#
	# labelValue1
	#
	$labelValue1.AutoSize = $True
	$labelValue1.Location = '464, 26'  
	$labelValue1.Name = 'labelValue1'  
	$labelValue1.Size = '40, 17'  
	$labelValue1.TabIndex = 19
	$labelValue1.Text = 'Value1'  
	$labelValue1.UseCompatibleTextRendering = $True
	#
	# textboxValue2
	#
	$textboxValue2.Location = '464, 89'  
	$textboxValue2.Name = 'textboxValue2'  
	$textboxValue2.Size = '121, 20'  
	$textboxValue2.TabIndex = 17
	#
	# textboxValue3
	#
	$textboxValue3.Location = '463, 135'  
	$textboxValue3.Name = 'textboxValue3'  
	$textboxValue3.Size = '122, 20'  
	$textboxValue3.TabIndex = 18
	#
	# textboxValue1
	#
	$textboxValue1.Location = '463, 46'  
	$textboxValue1.Name = 'textboxValue1'  
	$textboxValue1.Size = '122, 20'  
	$textboxValue1.TabIndex = 15
	#
	# datagridviewProjectUser
	#
	$datagridviewProjectUser.AllowUserToAddRows = $False
	$datagridviewProjectUser.ColumnHeadersHeightSizeMode = 'AutoSize'  
	$datagridviewProjectUser.Location = '12, 12'  
	$datagridviewProjectUser.Name = 'datagridviewProjectUser'  
	$datagridviewProjectUser.ReadOnly = $True
	$datagridviewProjectUser.SelectionMode = 'FullRowSelect'  
	$datagridviewProjectUser.ShowEditingIcon = $False
	$datagridviewProjectUser.Size = '445, 206'  
	$datagridviewProjectUser.TabIndex = 13
	#
	# buttonClose
	#
	$buttonClose.Anchor = 'Bottom, Right'  
	$buttonClose.CausesValidation = $False
	$buttonClose.DialogResult = 'Cancel'  
	$buttonClose.Location = '529, 226'  
	$buttonClose.Name = 'buttonClose'  
	$buttonClose.Size = '75, 23'  
	$buttonClose.TabIndex = 14
	$buttonClose.Text = '&Close'  
	$buttonClose.UseCompatibleTextRendering = $True
	$buttonClose.UseVisualStyleBackColor = $True
	$form1.ResumeLayout()
	#endregion Generated Form Code

	#----------------------------------------------

	#Save the initial state of the form
	$InitialFormWindowState = $form1.WindowState
	#Init the OnLoad event to correct the initial state of the form
	$form1.add_Load($Form_StateCorrection_Load)
	#Clean up the control events
	$form1.add_FormClosed($Form_Cleanup_FormClosed)
	#Show the Form
	return $form1.ShowDialog()

} #End Function

#Call the form
Show-DatagridviewExampleDatatable_psf | Out-Null

Das Zurückschreiben habe ich mal herausgenommen, weil meine Ansätze nicht funktioniert haben. Zum Datagridview sind meine Fragen:
1. Wenn ich dem DGV Zeilen hinzufüge, werden diese automatisch in die Datasource also meine Datatable geschrieben oder muss ich das selber machen?
2. Wenn es nicht in die Datatable geschrieben wird, wie kann ich einen synchronen Status zwischen Datatable und DGV sicherstellen?
3. Kann ich mein vorhaben so überhaupt umsetzen?

Gruß
derhoeppi

Content-Key: 392563

Url: https://administrator.de/contentid/392563

Printed on: April 19, 2024 at 17:04 o'clock

Mitglied: 137808
Solution 137808 Nov 14, 2018 updated at 12:23:44 (UTC)
Goto Top
Link your datatable to your gridview, it is always in sync with your GridView when you edit the contents of it.

Regards
Member: derhoeppi
derhoeppi Nov 16, 2018 at 10:20:46 (UTC)
Goto Top
Datatable is linked to my gridview:

$datagridviewProjectUser.DataSource = $dtValues 

But i cannot select or update an value in my gridview.
Member: Marvin-Ojoye-Powershell
Marvin-Ojoye-Powershell Apr 23, 2023 updated at 22:46:08 (UTC)
Goto Top
ich hab's mit folgenden Ansatz gemacht der erste Code Block ist das gesummte beispiel unten erkläre ich die einzelnen Schritte so das es im Windows Powershell ISE testbar ist:

veraussetzung ist die installation der Excel Module:
PS C:\Windows\system32> Install-Module -Name PSExcel -Force
PS C:\Windows\system32> Install-Module -Name ImportExcel -Force

Beispiel: UpdateExcelSample.ps1
Import-Module ImportExcel

function Edit-GridData {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,Mandatory = $true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName = $true
         )]
        [PSObject]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$false
        )]
        [string[]]
        $LockedColumns
    )

    $table = New-Object System.Data.DataTable
    $InputObject[0].PSObject.Properties.Name | ForEach-Object {
        $table.Columns.Add($_, [System.Type]::GetType("System.String")).Caption = $_  
    }

    $InputObject | ForEach-Object {
        $row = $table.NewRow()
        foreach ($column in $table.Columns) {
            $value = $_.($column.ColumnName).ToString()
            $row.($column.ColumnName) = $value
        }
        $table.Rows.Add($row)
    }

    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null  

    $grid = New-Object System.Windows.Forms.DataGridView
    $grid.AllowUserToAddRows = $true
    $grid.AllowUserToDeleteRows = $true
    $grid.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
    $grid.ColumnHeadersHeightSizeMode = 'AutoSize'  
    $grid.RowTemplate.Height = 30
    $grid.DataSource = $table
    
    # Set ReadOnly property of each row to True
    foreach ($row in $grid.Rows) {
        $row.ReadOnly = $true
    }

    $grid.Anchor = "None"  
    $grid.Dock = "Fill"  

    $buttonPanel = New-Object System.Windows.Forms.Panel
    $buttonPanel.Dock = "Bottom"  
    $buttonPanel.Height = 40
    $buttonPanel.Margin = '0, 0, 0, 0'  

    $okButton = New-Object System.Windows.Forms.Button
    $okButton.Text = "OK"  
    $okButton.Width = 80
    $okButton.Height = 30
    $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $okButton.Anchor = "Right"  


    $buttonPanel.Controls.Add($okButton)

    $dialog = New-Object System.Windows.Forms.Form
    $dialog.Text = "Edit Grid View"  
    $dialog.Width = 1600
    $dialog.Height = 1000
    $dialog.Controls.Add($grid)
    $dialog.Controls.Add($buttonPanel)

    $result = $dialog.ShowDialog()

    if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
         $output = @()
        foreach ($row in $grid.Rows) {
            $obj = New-Object System.Management.Automation.PSObject
            for ($i = 0; $i -lt $grid.Columns.Count; $i++) {
                $columnName = $grid.Columns[$i].DataPropertyName
                $columnValue = $row.Cells[$i].Value
                if (-not [string]::IsNullOrEmpty($columnValue)) {
                    $obj | Add-Member -MemberType NoteProperty -Name $columnName -Value $columnValue
                }
            }
            $output += $obj
        }
        return [PSObject]$output
    }
}

function overrideDataList {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [PSObject[]]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$true
        )]
        [PSObject[]]
        $updateData,
        
        [Parameter(
            Position=2,
            Mandatory=$true
        )]
        [String]
        $ByPropertyName
    )

    foreach ($update in $updateData) {
        $index = $InputObject."$ByPropertyName".IndexOf($update."$ByPropertyName")  
        if ($index -ne -1) {
            $InputObject[$index] = $update
        }
    }



    return $InputObject
}

# Create sample data
$sampleData = [PSCustomObject]@{
    Name = "John Doe"  
    Email = "johndoe@example.com"  
    Phone = "555-1234"  
}

$sampleData = Edit-GridData -InputObject $sampleData

# Export sample data to Excel file
$excelFile = ".\Phonebook.xlsx"  
$sampleData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"  

# Import data from Excel file
$importedData = Import-Excel -Path $excelFile -WorksheetName "Phonebook"  

# Edit data using grid view
$updatedData = Edit-GridData -InputObject $importedData

# Update imported data with edited data
$importedData = overrideDataList -InputObject $importedData -updateData $updatedData -ByPropertyName "Name"  

# Export updated data to Excel file
$importedData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"  

Function1 (Edit-GridData):
der Parameter -InputObject nimmt im jedes [PSobject] mit propertys af die String werte haben
$grid.DataSource = $table -> ist fürs Databinding zur editierbaren Grid Oberfläche
$table = New-Object System.Data.DataTable -> wird aus den schleifen gewonnen die die Felder der $InputObject
Variable in eine Datatabelle fürs grid umwandeln wie es in den For schleifen dargestellt ist.
der Rest des Codes ist für die Gestaltung der GUI.

im -> if ($result -eq [System.Windows.Forms.DialogResult]::OK) { ... }
code block wird die Grid Data Tabelle wider als [PSObject] über return zurückgegeben.

function Edit-GridData {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,Mandatory = $true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName = $true
         )]
        [PSObject]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$false
        )]
        [string[]]
        $LockedColumns
    )

    $table = New-Object System.Data.DataTable
    $InputObject[0].PSObject.Properties.Name | ForEach-Object {
        $table.Columns.Add($_, [System.Type]::GetType("System.String")).Caption = $_  
    }

    $InputObject | ForEach-Object {
        $row = $table.NewRow()
        foreach ($column in $table.Columns) {
            $value = $_.($column.ColumnName).ToString()
            $row.($column.ColumnName) = $value
        }
        $table.Rows.Add($row)
    }

    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null  

    $grid = New-Object System.Windows.Forms.DataGridView
    $grid.AllowUserToAddRows = $true
    $grid.AllowUserToDeleteRows = $true
    $grid.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
    $grid.ColumnHeadersHeightSizeMode = 'AutoSize'  
    $grid.RowTemplate.Height = 30
    $grid.DataSource = $table
    
    # Set ReadOnly property of each row to True
    foreach ($row in $grid.Rows) {
        $row.ReadOnly = $true
    }

    $grid.Anchor = "None"  
    $grid.Dock = "Fill"  

    $buttonPanel = New-Object System.Windows.Forms.Panel
    $buttonPanel.Dock = "Bottom"  
    $buttonPanel.Height = 40
    $buttonPanel.Margin = '0, 0, 0, 0'  

    $okButton = New-Object System.Windows.Forms.Button
    $okButton.Text = "OK"  
    $okButton.Width = 80
    $okButton.Height = 30
    $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $okButton.Anchor = "Right"  


    $buttonPanel.Controls.Add($okButton)

    $dialog = New-Object System.Windows.Forms.Form
    $dialog.Text = "Edit Grid View"  
    $dialog.Width = 1600
    $dialog.Height = 1000
    $dialog.Controls.Add($grid)
    $dialog.Controls.Add($buttonPanel)

    $result = $dialog.ShowDialog()

    if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
         $output = @()
        foreach ($row in $grid.Rows) {
            $obj = New-Object System.Management.Automation.PSObject
            for ($i = 0; $i -lt $grid.Columns.Count; $i++) {
                $columnName = $grid.Columns[$i].DataPropertyName
                $columnValue = $row.Cells[$i].Value
                if (-not [string]::IsNullOrEmpty($columnValue)) {
                    $obj | Add-Member -MemberType NoteProperty -Name $columnName -Value $columnValue
                }
            }
            $output += $obj
        }
        return [PSObject]$output
    }
}

Function2 (overrideDataList) ermöglicht es Änderungen eines PSOject Arrays durch ein anderes zu ergänzen:
hierbei muss eine initiale property verwendet werden die die Auswahl trigert wie zum beispiel die Name property
im späteren Beispiel von: $index = $InputObject."$ByPropertyName".IndexOf($update."$ByPropertyName")
$update in der forschleife befüllt das $InputObject mit den Änderungen.
function overrideDataList {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [PSObject[]]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$true
        )]
        [PSObject[]]
        $updateData,
        
        [Parameter(
            Position=2,
            Mandatory=$true
        )]
        [String]
        $ByPropertyName
    )

    foreach ($update in $updateData) {
        $index = $InputObject."$ByPropertyName".IndexOf($update."$ByPropertyName")  
        if ($index -ne -1) {
            $InputObject[$index] = $update
        }
    }



    return $InputObject
}


Anwendung beider Funktionen.

der Sample code eigenes [PSObject] um die Tabelle in Grid anzulegen die Phonebook.xlsx soll das speichern demonstrieren.:
# Create sample data
$sampleData = [PSCustomObject]@{
    Name = "John Doe"  
    Email = "johndoe@example.com"  
    Phone = "555-1234"  
}

$sampleData = Edit-GridData -InputObject $sampleData

ist um die Excel mit den eigenen eingaben zu betanken:

- Implementierung:
# Export sample data to Excel file
$excelFile = ".\Phonebook.xlsx"  
$sampleData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"  

nun lädt man sich die datei nochmal um mit dem grid dialog aus der Edit-GridData -InputObject $importedData
die daten zu laden die man ändern oder überschreiben möchte:

# Import data from Excel file
$importedData = Import-Excel -Path $excelFile -WorksheetName "Phonebook"  

# Edit data using grid view
$updatedData = Edit-GridData -InputObject $importedData

nun werden die Änderungen eingespeist durch:
overrideDataList -InputObject $importedData -updateData $updatedData -ByPropertyName "Name"

wichtig der Name btw. -ByPropertyName "Name" die werte des Colums müssen sich entsprechen aus
$importedData und $updatedData damit das ändern funktioniert.

Beispiel:

# Edit data using grid view
$updatedData = Edit-GridData -InputObject $importedData

# Update imported data with edited data
$importedData = overrideDataList -InputObject $importedData -updateData $updatedData -ByPropertyName "Name"  

nun der Export zum überschreiben der Excel mit den übernommenen Änderungen:

  1. Export updated data to Excel file
$importedData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"
Member: Marvin-Ojoye-Powershell
Marvin-Ojoye-Powershell Apr 23, 2023 updated at 23:41:17 (UTC)
Goto Top
probier das update mit:
# Select Relevant Data Rows
$selectdata = [PSObject] @($importedData | Out-GridView -OutputMode Multiple -Title "wähle Zeilen zum ändern aus" | Select-Object $importedData[0].PSObject.Properties.Name)  

# Edit data using grid view
$updatedData = Edit-GridData -InputObject ($selectdata)
Beispiel: UpdateExcelSample.ps1
Import-Module ImportExcel

function Edit-GridData {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,Mandatory = $true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName = $true
         )]
        [PSObject]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$false
        )]
        [string[]]
        $LockedColumns
    )

    $table = New-Object System.Data.DataTable
    $InputObject[0].PSObject.Properties.Name | ForEach-Object {
        $table.Columns.Add($_, [System.Type]::GetType("System.String")).Caption = $_  
    }

    $InputObject | ForEach-Object {
        $row = $table.NewRow()
        foreach ($column in $table.Columns) {
            
            if($null -eq $_.($column.ColumnName)){
                $value = ""  
            } else {
                $value = $_.($column.ColumnName).ToString()
            }
            
            $row.($column.ColumnName) = $value
        }
        $table.Rows.Add($row)
    }

    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null  

    $grid = New-Object System.Windows.Forms.DataGridView
    $grid.AllowUserToAddRows = $true
    $grid.AllowUserToDeleteRows = $true
    $grid.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
    $grid.ColumnHeadersHeightSizeMode = 'AutoSize'  
    $grid.RowTemplate.Height = 30
    $grid.DataSource = $table
    
    # Set ReadOnly property of each row to True
    foreach ($row in $grid.Rows) {
        $row.ReadOnly = $true
    }

    $grid.Anchor = "None"  
    $grid.Dock = "Fill"  

    $buttonPanel = New-Object System.Windows.Forms.Panel
    $buttonPanel.Dock = "Bottom"  
    $buttonPanel.Height = 40
    $buttonPanel.Margin = '0, 0, 0, 0'  

    $okButton = New-Object System.Windows.Forms.Button
    $okButton.Text = "OK"  
    $okButton.Width = 80
    $okButton.Height = 30
    $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $okButton.Anchor = "Right"  


    $buttonPanel.Controls.Add($okButton)

    $dialog = New-Object System.Windows.Forms.Form
    $dialog.Text = "Edit Grid View"  
    $dialog.Width = 1600
    $dialog.Height = 1000
    $dialog.Controls.Add($grid)
    $dialog.Controls.Add($buttonPanel)

    $result = $dialog.ShowDialog()

    if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
         $output = @()
        foreach ($row in $grid.Rows) {
            $obj = New-Object System.Management.Automation.PSObject
            for ($i = 0; $i -lt $grid.Columns.Count; $i++) {
                $columnName = $grid.Columns[$i].DataPropertyName
                $columnValue = $row.Cells[$i].Value
                if (-not [string]::IsNullOrEmpty($columnValue)) {
                    $obj | Add-Member -MemberType NoteProperty -Name $columnName -Value $columnValue
                }
            }
            $output += $obj
        }
        return [PSObject]$output
    }
}

function overrideDataList {

    [CmdletBinding()]
    param(
        [Parameter(
            Position=0,
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [PSObject[]]
        $InputObject,
        
        [Parameter(
            Position=1,
            Mandatory=$true
        )]
        [PSObject[]]
        $updateData,
        
        [Parameter(
            Position=2,
            Mandatory=$true
        )]
        [String]
        $ByPropertyName
    )

    foreach ($update in $updateData) {
        $index = $InputObject."$ByPropertyName".IndexOf($update."$ByPropertyName")  
        if ($index -ne -1) {
            $InputObject[$index] = $update
        }
    }



    return $InputObject
}


# Create sample data
$sampleData = [PSCustomObject]@{
    Name = "John Doe"  
    Email = "johndoe@example.com"  
    Phone = "555-1234"  
}

$sampleData = Edit-GridData -InputObject $sampleData

# Export sample data to Excel file
$excelFile = ".\Phonebook.xlsx"  
$sampleData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"  

# Import data from Excel file
$importedData = Import-Excel -Path $excelFile -WorksheetName "Phonebook"  

# Select Relevant Data Rows
$selectdata = [PSObject] @($importedData | Out-GridView -OutputMode Multiple -Title "wähle Zeilen zum ändern aus" | Select-Object $importedData[0].PSObject.Properties.Name)  

# Edit data using grid view
$updatedData = Edit-GridData -InputObject ($selectdata)

# Update imported data with edited data
$importedData = overrideDataList -InputObject $importedData -updateData $updatedData -ByPropertyName "Name"  

# Export updated data to Excel file
$importedData | Export-Excel -Path $excelFile -AutoSize -TableName "Phonebook" -WorksheetName "Phonebook"