I'm having a hard time trying to figure out how I can update ListView Items in multithread using the DataContext instead of a Dispatcher Invoke. As you will notice in my example, if you uncomment the ListView Refresh line it works as intended but the purpose of binding in the first place is to avoid refreshing the whole list as it slows down the process, especially on another thread using a dispatcher. If someone would be kind enough to point me in the right direction, it would be greatly appreciated, Thank you!
$Global:SyncHash = @{}
Add-Type –assemblyName WindowsBase
Add-Type –assemblyName PresentationCore
Add-Type –assemblyName PresentationFramework
[xml]$XAML = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MVVM Example" Height="200" Width="300">
<DockPanel Margin="10">
<Button DockPanel.Dock="Top" Content="Change Name" Margin="0,0,0,10" Height="20" Name="Button"/>
<ListView Name="ListView">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False" >
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" Width="120" DisplayMemberBinding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</Window>
"@
$XamlReader = New-Object System.Xml.XmlNodeReader $XAML
$SyncHash.GUI = [Windows.Markup.XamlReader]::Load($XamlReader)
$XAML.SelectNodes("//*[@Name]") | ForEach-Object { $SyncHash.Add($_.Name,$SyncHash.GUI.FindName($_.Name)) }
$Names = "Julian","Romeo","Petrovski"
$Ages = "35","44","28"
$Items = @()
For ([Int]$i = 0; $i -lt $Names.Count; $i++) {
$Items += [PSObject]@{
Name=$Names[$i]
Age=$Ages[$i]
}
}
$SyncHash.ItemsList = $Items
$DataSource = New-Object System.Collections.ObjectModel.ObservableCollection[PSObject]
$DataSource.Add($SyncHash)
$SyncHash.GUI.DataContext = $DataSource
$Binding = New-Object System.Windows.Data.Binding -ArgumentList "ItemsList"
$Binding.Mode = [System.Windows.Data.BindingMode]::TwoWay
[void][System.Windows.Data.BindingOperations]::SetBinding($SyncHash.ListView,[System.Windows.Controls.ListView]::ItemsSourceProperty, $Binding)
$SyncHash.Button.Add_Click({
$FinishedRS = Get-Runspace | Where-Object { $_.RunspaceAvailability -ne "Busy" }
If ($FinishedRS) {
$FinishedRS.Dispose()
}
$ScriptBlock = {
Param ($DataSource)
$DataSource.ItemsList[1].Name = "Denis"
<#$Global:SyncHash.GUI.Dispatcher.Invoke(
[action]{
$SyncHash.ListView.Items.Refresh()
},"Normal"
)#>
}
$InitialSessionState = [InitialSessionState]::CreateDefault()
$Script:Runspace = [RunspaceFactory]::CreateRunspace($InitialSessionState)
$Runspace.ApartmentState = "STA"
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("SyncHash",$Global:SyncHash)
$Script:PSCmd = [PowerShell]::Create()
[void]$PSCmd.AddScript($ScriptBlock)
[void]$PSCmd.AddArgument($DataSource)
$PSCmd.Runspace = $Runspace
$Script:Handle = $PSCmd.BeginInvoke()
})
$SyncHash.GUI.ShowDialog() | Out-Null