derhoeppi
Goto Top

Powershell ListView DataGrid in WPF

Hallo,

ich habe in einer xaml Datei ein ListView Element erstellt. Die xaml Datei wird durch das PowerShell Skript eingebunden und stellt damit das Frontend bereit. In dem ListView gibt es drei Spalten (Vorname, Nachname, Login). Mein aktuelles Problem besteht darin die ListView mit Daten zu füllen, die ich aus TextBoxen auslese.

In der xaml Datei ist die ListView wie folg eingebunden:
<ListView x:Name="LV_User" HorizontalAlignment="Left" Height="195.723" Margin="10,10,0,0" VerticalAlignment="Top" Width="253.566" Grid.ColumnSpan="2">  
                        <ListView.View>
                            <GridView>
                                <GridViewColumn Header="Vorname"/>  
                                <GridViewColumn Header="Nachname"/>  
                                <GridViewColumn Header="Login"/>  
                            </GridView>
 </ListView.View>

Im Powershell Skript wird das Element wie folgt eingebunden:

$LV_User = $Form.FindName('LV_User')  

Ich versuche nun diese ListView zu füllen. Aber außer das mit eine neue Zeile angelegt wird, passiert nichts (Zeile wird ohne Spalteninhalt angelegt). Zum hinzufügen von Inhalt nutze ich folgedes.
$LV_User.Items.Add($Vorname).SubItems.AddRange(@($Nachname,$Login))

Selbst wenn ich das Hinzufügen Zeile mit statischen Werten versuche, wird zwar die Zeile angelegt, aber ohne Inhalt. Woran scheiter ich?

Gruß
derhoeppi

Content-Key: 284370

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

Printed on: April 20, 2024 at 11:04 o'clock

Member: colinardo
Solution colinardo Oct 01, 2015, updated at Oct 02, 2015 at 08:36:16 (UTC)
Goto Top
Hallo derhoeppi,
Ist eigentlich ähnlich zu meinem Beispiel mit dem DataGrid in meinem letzten Posting ...(DataSource erstellen und der ItemSource des ListView zuordnen)
Add-Type -AssemblyName Presentationframework
[string]$xaml = @"  
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Window" Title="ListView Demo" WindowStartupLocation = "CenterScreen" ResizeMode="NoResize" ShowInTaskbar = "True" Width="448" Height="262">  
    <Grid Name="Grid1">  
        <ListView x:Name="LV_User" HorizontalAlignment="Left" Height="199" Margin="10,10,10,10" VerticalAlignment="Top" Width="253" ItemsSource="{Binding}">  
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding }" />  
                    <GridViewColumn Header="Nachname" DisplayMemberBinding="{Binding [1]}"/>  
                    <GridViewColumn Header="Loginname" DisplayMemberBinding="{Binding [2]}" />  
                </GridView>
            </ListView.View>
        </ListView>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,12,0,0" Name="txtVorname" VerticalAlignment="Top" Width="120" Text="Max" />  
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,41,0,0" Name="txtNachname" VerticalAlignment="Top" Width="120" Text="Mustermann" />  
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,70,0,0" Name="txtLoginname" VerticalAlignment="Top" Width="120" Text="maxmustermann" />  
        <Button Content="Add" Height="23" HorizontalAlignment="Left" Margin="322,99,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />  
    </Grid>
    <Window.Background>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">  
            <GradientStop Color="#FFC1C1C1" Offset="0" />  
            <GradientStop Color="White" Offset="1" />  
        </LinearGradientBrush>
    </Window.Background>
</Window>

"@  
# Markup laden 
$window=[Windows.Markup.XamlReader]::Parse($xaml)

$dt = new-Object System.Data.DataTable
[void]$dt.Columns.Add("Vorname")  
[void]$dt.Columns.Add("Nachname")  
[void]$dt.Columns.Add("Loginname")  

$lv = $window.FindName('LV_User')  
$btn = $window.FindName('Button1')  
$txtVorname = $window.FindName('txtVorname')  
$txtNachname = $window.FindName('txtNachname')  
$txtLoginname = $window.FindName('txtLoginname')  

$lv.ItemsSource = $dt.DefaultView

$btn.add_Click({
    $dt.Rows.Add(@($txtVorname.Text,$txtNachname.Text,$txtLoginname.Text))
})


$async = $window.Dispatcher.InvokeAsync({$window.ShowDialog() | Out-Null})
$async.Wait() | Out-Null
p.s. es hilft ungemein das vorher mit VisualStudio in VB.Net oder C# zu coden und erst dann auf Powershell zu übertragen, denn in VisualStudio ist das Debugging wesentlich einfacher.

Grüße Uwe

Falls der Beitrag gefällt, seid so nett und unterstützt mich durch eine kleine Spende / If you like my contribution please support me and donate
Member: derhoeppi
derhoeppi Oct 02, 2015 at 08:58:35 (UTC)
Goto Top
Hallo Uwe,

ich finde zwar keinen Unterschied zu meinen gestrigen Versuchen, aber es funktioniert nun. Nun bin ich damit beschäftigt die Daten von dort auszulesen oder eben bei Fehleingaben zu löschen.

Ich denke eigentlich das ich mit SelectedItems an die markierte Zeile gelange. Leider ist die Variable in die ich das SelectedItems schreibe leer.


foreach($item in$LV_User.SelectedItems) {
Write-Host $item.Text
}

Im Internet habe ich leider keine Information gefunden, ob ich die ganze Zeile auslesen oder nur den Inhalt aus z.B. der ersten Spalte.

Gruß
derhoeppi
Member: colinardo
colinardo Oct 02, 2015 updated at 09:14:43 (UTC)
Goto Top
ich finde zwar keinen Unterschied zu meinen gestrigen Versuchen, aber es funktioniert nun.
Genau hinschauen face-smile
Nun bin ich damit beschäftigt die Daten von dort auszulesen
Kein Problem. Die Elemente die du bei SelectedItems übergeben bekommst sind vom Typ DataRowView und bei diesen lassen sich die Spalten als Index abfragen:
$LVUser_SelectedItems | %{
    $vorname = $_
    $nachname = $_[1]
    # usw.
}
Andere alternative ist das nutzen von SelectedIndices und dann abfragen der Datenquelle des ListViews.

Wie ich geschrieben habe, mach es erst in VisualStudio dort hast du alle Debugging-Möglichkeiten und die Intellisense die dir die verfügbaren Eigenschaften und Klassen anzeigt. Damit ist das ein Kinderspiel., und du musst nicht immer Google quälen, gleichzeitig lernt man viel mehr ... das umsetzen in Powershell ist dann nur noch Makulatur.

Grüße Uwe
Member: derhoeppi
derhoeppi Oct 05, 2015 at 09:57:00 (UTC)
Goto Top
Hallo Uwe,

ich stelle mich hier zu glatt an. Ich wollte nun deinem Vorschlag folgen und das ganze in VisualStudio als C# oder VB nachstellen. Problem ist aber das ich dort wieder extrem umdenken muss, weil das deklarieren von Variablen etc. anders abläuft.

Aus diesem Grund bin ich nun wieder in mein PowerShell Skript gewechselt. Dort wollte ich nun das Löschen eines selektierenten Items vornehmen.

Foreach($ListviewItem in $LV_User.SelectedItems){
$LV_User.Items.Remove($ListvieItem)
}

Bei der Codeausführung erhalte ich jedoch den Error, dass die ItemSource noch in Benutzung ist. Kannst du mir dabei noch einmal helfen. Ich hoffe danach habe ich das was ich für das Skript benötige. Einzige Frage wäre noch, ob ich mit den SelectedIndices die komplette Zeile oder nur Spalten zurückerhalte? Zum Schluss möchte ich die gesamte Listview (Inhalt) in ein Array schreiben.

Gruß
derhoeppi
Member: colinardo
Solution colinardo Oct 05, 2015 updated at 12:03:17 (UTC)
Goto Top
Hmm, du verstehst leider das Konzept hinter dem Verknüpfen zwischen der Data-Source (also der Data-Table) welche die Daten für das ListView-Element bereitstellt noch nicht. Du kannst bei dieser Methode nicht direkt die Elemente des ListView-Controls ändern sondern musst die verknüpfte Datenquelle also die erstellte DataTable ($dt) ändern !
Mit dieser Datenquelle $dt.Rows hast du auch gleichzeitig ein Array über das du für deinen Export iterieren kannst...
Einfach mal die Doku zum Datatable Objekt studieren ... Powershell == .NET also fast 1:1 umsetzbar.

Du hättest besser erst mit Windows-Forms angefangen, WPF ist eine Stufe höher und für den Anfänger nicht ganz so simpel umzusetzen, wie Windows Forms.

Beispiel mit "Remove"-Button.
Add-Type -AssemblyName Presentationframework
[string]$xaml = @"  
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Window" Title="ListView Demo" WindowStartupLocation = "CenterScreen" ResizeMode="NoResize" ShowInTaskbar = "True" Width="448" Height="262">  
    <Grid Name="Grid1">  
        <ListView x:Name="LV_User" HorizontalAlignment="Left" Height="199" Margin="10,10,10,10" VerticalAlignment="Top" Width="253" ItemsSource="{Binding}">  
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Vorname" DisplayMemberBinding="{Binding }" />  
                    <GridViewColumn Header="Nachname" DisplayMemberBinding="{Binding [1]}"/>  
                    <GridViewColumn Header="Loginname" DisplayMemberBinding="{Binding [2]}" />  
                </GridView>
            </ListView.View>
        </ListView>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,12,0,0" Name="txtVorname" VerticalAlignment="Top" Width="120" Text="Max" />  
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,41,0,0" Name="txtNachname" VerticalAlignment="Top" Width="120" Text="Mustermann" />  
        <TextBox Height="23" HorizontalAlignment="Left" Margin="277,70,0,0" Name="txtLoginname" VerticalAlignment="Top" Width="120" Text="maxmustermann" />  
        <Button Content="Add" Height="23" HorizontalAlignment="Left" Margin="322,99,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />  
        <Button Content="Remove" Height="23" HorizontalAlignment="Left" Margin="322,130,0,0" Name="Button2" VerticalAlignment="Top" Width="75" />  

    </Grid>
    <Window.Background>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">  
            <GradientStop Color="#FFC1C1C1" Offset="0" />  
            <GradientStop Color="White" Offset="1" />  
        </LinearGradientBrush>
    </Window.Background>
</Window>

"@  
# Markup laden 
$window=[Windows.Markup.XamlReader]::Parse($xaml)

$dt = new-Object System.Data.DataTable
[void]$dt.Columns.Add("Vorname")  
[void]$dt.Columns.Add("Nachname")  
[void]$dt.Columns.Add("Loginname")  

$lv = $window.FindName('LV_User')  
$btnAdd = $window.FindName('Button1')  
$btnRemove = $window.FindName('Button2')  
$txtVorname = $window.FindName('txtVorname')  
$txtNachname = $window.FindName('txtNachname')  
$txtLoginname = $window.FindName('txtLoginname')  

$lv.ItemsSource = $dt.DefaultView

$btnAdd.add_Click({
    $dt.Rows.Add(@($txtVorname.Text,$txtNachname.Text,$txtLoginname.Text))
})
$btnRemove.add_Click({
    if ($lv.SelectedIndex -ne -1){
        $dt.Rows.RemoveAt($lv.SelectedIndex)
    }
})

$async = $window.Dispatcher.InvokeAsync({$window.ShowDialog() | Out-Null})
$async.Wait() | Out-Null
Grüße Uwe
Member: derhoeppi
derhoeppi Oct 06, 2015 at 10:03:49 (UTC)
Goto Top
Hallo Uwe,

vielen Dank für die großartige Unterstützung. Für die Integration des Listview muss ich wirklich nur noch eine Frage stellen. Du schreibst das ich via $dt.Rows an den Inhalt des Array $dt gelange. Das Array $dt enthält soviele Items wie ich Zeilen im Listview erzeugt habe. Wenn ich mir mit GetType() den Typ des Array Items ausgeben lasse erhalte ich den Wert System.Data.DataRow. Soweit verstehe ich das auch. Um an die Werte zu gelangen kann ich dann ja mit
foreach ($i in $dt){
    $vorname = $_
    $nachname = $_[1]
    $login = $_[2]
Write-Host $vorname
Write-Host $nachname
Write-Host $login
}

an die einzelnen Inhalte gelangen. Am liebsten würde ich die Abstraktion / Verschachtelung aufheben, so dass der Inhalt der DataRow Elemente geordnet in ein einfaches Array geschrieben werden (quasi so als ob ich einen Userdaten aus einer CSV importiere).
Um das Problem zu lösen habe ich mir für DataTable die Methoden Select und ToString angesehen. Mit diesen beiden Methoden komme ich jedoch nicht weiter, weil sie das Verhalten nicht ändern. Andere Beispiele die ich im Internet zu C# oder VB gefunden habe, konnte ich ebenfalls nicht umwandeln, so dass ich mit einem write-host $Array den kompletten Inhalt im Klartext ausgibt.

Gruß
derhoeppi
Member: colinardo
Solution colinardo Oct 06, 2015 updated at 11:30:51 (UTC)
Goto Top
Kannst du so machen:
$obj = @() 
$dt.Rows | %{
    $cols = $_.ItemArray
    $obj += New-Object PSObject -Property @{"Vorname"=$cols;"Nachname"=$cols[1];"LoginName"=$cols[2]}  
}
$obj ist dann dein PSObject ...

Grüße Uwe

p.s. dein Schnippsel ist nicht ganz richtig ... In dem Fall ist es in der Schleife nicht $_ sondern $i face-wink
foreach ($i in $dt){
$vorname = $_
$nachname = $_[1]
$login = $_[2]