WPF Progressbar in Powershell aktualisieren
Hallo Zusammen,
ich hab schon viele Einträge hier gelesen, aber noch nicht so ganz verstanden, wieso es bei mir nicht funktioniert.
Das Problem was ich habe ist, dass ich via Powershell ein Backupskript geschrieben habe was super funktioniert. Ein Kollege möchte jetzt noch eine Progressbar haben die den aktuellen Stand anzeigt.
Also habe ich eine XAML-WPF-Gui zusammengeklickt und möchte das jetzt via Runspace aktualisieren, je nachdem wie viele Daten schon kopiert wurden.
Anbei der Sourcecode:
Für Tipps bin ich euch sehr Dankbar!
VG
tzabbi
ich hab schon viele Einträge hier gelesen, aber noch nicht so ganz verstanden, wieso es bei mir nicht funktioniert.
Das Problem was ich habe ist, dass ich via Powershell ein Backupskript geschrieben habe was super funktioniert. Ein Kollege möchte jetzt noch eine Progressbar haben die den aktuellen Stand anzeigt.
Also habe ich eine XAML-WPF-Gui zusammengeklickt und möchte das jetzt via Runspace aktualisieren, je nachdem wie viele Daten schon kopiert wurden.
Anbei der Sourcecode:
#region XAML window definition
# Right-click XAML and choose WPF/Edit... to edit WPF Design
# in your favorite WPF editing tool
$xaml = @'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
MinWidth="200"
Width ="400"
SizeToContent="Height"
Title="Backup"
Topmost="True" Height="250.77">
<Grid>
<Label Content="Gesamtfortschritt:" HorizontalAlignment="Left" Margin="20,3,0,0" VerticalAlignment="Top"/>
<ProgressBar HorizontalAlignment="Left" Height="20" Margin="20,34,0,0" VerticalAlignment="Top" Width="351" Minimum="0" Maximum="100" Value="60" Name="pbStatusTotal"/>
<TextBlock Text="{Binding ElementName=pbStatusTotal, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="188,36,182,168" />
<Label Content="Aktueller Ordner:" HorizontalAlignment="Left" Margin="20,59,0,0" VerticalAlignment="Top"/>
<ProgressBar HorizontalAlignment="Left" Height="20" Margin="20,90,0,0" VerticalAlignment="Top" Width="351" Minimum="0" Maximum="100" Value="60" Name="pbStatusCurrentDirectory"/>
<TextBlock Text="{Binding ElementName=pbStatusCurrentDirectory, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="188,92,182,112" RenderTransformOrigin="0.31,0.521" />
</Grid>
</Window>
'@
#endregion
#region Code Behind
function Convert-XAMLtoWindow
{
param
(
[Parameter(Mandatory=$true)]
[string]
$XAML
)
Add-Type -AssemblyName PresentationFramework
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
$result = [Windows.Markup.XAMLReader]::Load($reader)
$reader.Close()
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
while ($reader.Read())
{
$name=$reader.GetAttribute('Name')
if (!$name) { $name=$reader.GetAttribute('x:Name') }
if($name)
{$result | Add-Member NoteProperty -Name $name -Value $result.FindName($name) -Force}
}
$reader.Close()
$result
}
function Show-WPFWindow
{
param
(
[Parameter(Mandatory=$true)]
[Windows.Window]
$Window
)
$result = $null
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
#endregion Code Behind
#region Convert XAML to Window
$window = Convert-XAMLtoWindow -XAML $xaml
#endregion
#region Manipulate Window Content
$pbStatusTotal = $window.FindName('pbStatusTotal')
$pbStatusTotal.Value = $i
#endregion
$syncHash = [hashtable]::Synchronized(@{})
$syncHash.pbStatusTotal = $pbStatusTotal
$newPowershell = [powershell]::Create()
$newRunspace = [runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$code = { foreach ($i in (1..100))
{
Start-Sleep -Milliseconds 100
Write-Host $i
$syncHash.pbStatusTotal.Value = 50
}
}
$newPowershell.AddScript({
# in this expample we set the progress-bar value every 500 ms
for ($i = 1;$i -le 10;$i++){
sleep -Milliseconds 500
$syncHash.pbStatusTotal.Value = $i * 10
}
})
$newPowershell.Runspace = $newRunspace
$handle = $newPowershell.BeginInvoke()
# Show Window
$result = Show-WPFWindow -Window $window
Für Tipps bin ich euch sehr Dankbar!
VG
tzabbi
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 558008
Url: https://administrator.de/contentid/558008
Ausgedruckt am: 19.12.2024 um 15:12 Uhr
5 Kommentare
Neuester Kommentar
Servus,
Das wäre die eine Möglichkeit, die andere arbeitet mit einem Dispatcher-Timer, das kannst du dir hier abschauen
http://tiberriver256.github.io/powershell/PowerShellProgress-Pt3/
Grüße Uwe
wieso es bei mir nicht funktioniert.
WPF ist hier ein wenig anders gestrickt was das Multithreading betrifft, dein kopierter Code aus einem meiner Beiträge hier war nur für einfache Windows-Forms gedacht, nicht für WPF .#region XAML window definition
# Right-click XAML and choose WPF/Edit... to edit WPF Design
# in your favorite WPF editing tool
$xaml = @'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
MinWidth="200"
Width ="400"
SizeToContent="Height"
Title="Backup"
Topmost="True" Height="250.77">
<Grid>
<Label Content="Gesamtfortschritt:" HorizontalAlignment="Left" Margin="20,3,0,0" VerticalAlignment="Top"/>
<ProgressBar Height="20" Margin="20,34,20,0" VerticalAlignment="Top" Minimum="0" Maximum="100" Value="0" Name="pbStatusTotal"/>
<TextBlock Text="{Binding ElementName=pbStatusTotal, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" Margin="188,36,182,168" />
<Label Content="Aktueller Ordner:" HorizontalAlignment="Left" Margin="20,59,0,0" VerticalAlignment="Top"/>
<ProgressBar Height="20" Margin="20,90,20,0" VerticalAlignment="Top" Minimum="0" Maximum="100" Value="60" Name="pbStatusCurrentDirectory"/>
<TextBlock Text="{Binding ElementName=pbStatusCurrentDirectory, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" Margin="188,92,182,112" RenderTransformOrigin="0.31,0.521" />
</Grid>
</Window>
'@
#endregion
#region Code Behind
function Convert-XAMLtoWindow
{
param
(
[Parameter(Mandatory=$true)]
[string]
$XAML
)
Add-Type -AssemblyName PresentationFramework
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
$result = [Windows.Markup.XAMLReader]::Load($reader)
$reader.Close()
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
while ($reader.Read())
{
$name=$reader.GetAttribute('Name')
if (!$name) { $name=$reader.GetAttribute('x:Name') }
if($name)
{$result | Add-Member NoteProperty -Name $name -Value $result.FindName($name) -Force}
}
$reader.Close()
$result
}
function Show-WPFWindow
{
param
(
[Parameter(Mandatory=$true)]
[Windows.Window]
$Window
)
$result = $null
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
#endregion Code Behind
#region Convert XAML to Window
$window = Convert-XAMLtoWindow -XAML $xaml
#endregion
#region Manipulate Window Content
$pbStatusTotal = $window.FindName('pbStatusTotal')
$pbStatusTotal.Value = 0
#endregion
$syncHash = [hashtable]::Synchronized(@{})
$syncHash.pbStatusTotal = $pbStatusTotal
$newRunspace = [runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$newPowershell = [powershell]::Create()
$newPowershell.AddScript({
# in this expample we set the progress-bar value every 500 ms
for ($i = 1;$i -le 10;$i++){
sleep -Milliseconds 100
$syncHash.pbStatusTotal.Dispatcher.Invoke("Normal", [action]{$syncHash.pbStatusTotal.Value=$i *10})
}
}) | out-null
$newPowershell.Runspace = $newRunspace
$window.add_ContentRendered({
$handle = $newPowershell.BeginInvoke()
})
# Show Window
$result = Show-WPFWindow -Window $window
http://tiberriver256.github.io/powershell/PowerShellProgress-Pt3/
Grüße Uwe
Wünsche ich dir ebenso.
Hier noch als Ergänzung dein obiges Beispiel mit der oben schon angesprochenen alternativen Variante Dispatcher-Timer Variante umgesetzt. Den TimeSpan für den Timer kann man natürlich an seine Gegebenheiten anpassen, ist jetzt nur für das schnelle Beispiel auf eine zehntel Sekunde gesetzt.
Grüße Uwe
Hier noch als Ergänzung dein obiges Beispiel mit der oben schon angesprochenen alternativen Variante Dispatcher-Timer Variante umgesetzt. Den TimeSpan für den Timer kann man natürlich an seine Gegebenheiten anpassen, ist jetzt nur für das schnelle Beispiel auf eine zehntel Sekunde gesetzt.
#region XAML window definition
# Right-click XAML and choose WPF/Edit... to edit WPF Design
# in your favorite WPF editing tool
$xaml = @'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
MinWidth="200"
Width ="400"
Title="Backup"
Topmost="True" Height="200">
<Grid>
<Label Content="Gesamtfortschritt:" HorizontalAlignment="Left" Margin="20,3,0,0" VerticalAlignment="Top"/>
<ProgressBar Height="20" Margin="20,34,20,0" VerticalAlignment="Top" Minimum="0" Maximum="100" Value="0" Name="pbStatusTotal"/>
<TextBlock Text="{Binding ElementName=pbStatusTotal, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" Margin="20,36,20,0" />
<Label Content="Aktueller Ordner:" HorizontalAlignment="Left" Margin="20,59,0,0" VerticalAlignment="Top"/>
<ProgressBar Height="20" Margin="20,90,20,0" VerticalAlignment="Top" Minimum="0" Maximum="100" Value="60" Name="pbStatusCurrentDirectory"/>
<TextBlock Text="{Binding ElementName=pbStatusCurrentDirectory, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Center" Margin="20,92,20,0"/>
</Grid>
</Window>
'@
#endregion
#region Code Behind
function Convert-XAMLtoWindow
{
param
(
[Parameter(Mandatory=$true)]
[string]
$XAML
)
Add-Type -AssemblyName PresentationFramework
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
$result = [Windows.Markup.XAMLReader]::Load($reader)
$reader.Close()
$reader = [XML.XMLReader]::Create([IO.StringReader]$XAML)
while ($reader.Read())
{
$name=$reader.GetAttribute('Name')
if (!$name) { $name=$reader.GetAttribute('x:Name') }
if($name)
{$result | Add-Member NoteProperty -Name $name -Value $result.FindName($name) -Force}
}
$reader.Close()
$result
}
function Show-WPFWindow
{
param
(
[Parameter(Mandatory=$true)]
[Windows.Window]
$Window
)
$result = $null
$null = $window.Dispatcher.InvokeAsync{
$result = $window.ShowDialog()
Set-Variable -Name result -Value $result -Scope 1
}.Wait()
$result
}
#endregion Code Behind
#region Convert XAML to Window
$window = Convert-XAMLtoWindow -XAML $xaml
#endregion
#region Manipulate Window Content
$pbStatusTotal = $window.FindName('pbStatusTotal')
$pbStatusTotal.Value = 0
#endregion
$syncHash = [hashtable]::Synchronized(@{})
$syncHash.pbValue = 0
$newRunspace = [runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$newPowershell = [powershell]::Create()
$newPowershell.AddScript({
# sampe for long running action with update to progressbar
1..10 | %{$syncHash.pbValue = $_ * 10; sleep -Milliseconds 250}
}) | out-null
# create dispatcher timer on window
$window.add_SourceInitialized({
$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.Interval = [Timespan]'0:0:0.10'
# timer action update progressbar value
$timer.Add_Tick({$pbStatusTotal.Value = $syncHash.pbValue})
$timer.Start()
})
# assign runspace and start script
$newPowershell.Runspace = $newRunspace
$handle = $newPowershell.BeginInvoke()
# Show Window
$result = Show-WPFWindow -Window $window
Grüße Uwe