如何加速将PowerShell数组数据导入WPF DataGrid?
Hey there! Let's fix that slow DataGrid item import you're dealing with. Your current loop-based approach is causing unnecessary UI updates and redundant object creation—here's a much more efficient way to handle bulk data loading:
First, Let's Clean Up the XAML
Your existing DataGrid has both AutoGenerateColumns="True" and manually defined columns, which will result in duplicate columns. Disable auto-generation since you've already specified the columns you need:
<DataGrid x:Name="DataGrid_DisabledAccounts" Background="#FF616161" Foreground="Black" AutoGenerateColumns="False" <!-- Changed from True to avoid duplicate columns --> SelectionMode="Extended"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> <DataGridTextColumn Header="SamAccountName" Binding="{Binding SamAccountName}"/> <DataGridTextColumn Header="distinguishedName" Binding="{Binding distinguishedName}"/> </DataGrid.Columns> </DataGrid>
Optimized PowerShell Code
The key issue with your current code is that adding items one-by-one and calling Items.Refresh() on each iteration forces the UI to redraw constantly. Instead, we'll use a WPF-friendly collection to load all data at once, then bind it to the DataGrid.
Step 1: Efficiently Fetch AD Data
First, optimize your AD query to avoid redundant property lookups (we'll fetch the Enabled property directly instead of implicitly querying ADUser twice):
# Get disabled users from the group (optimized AD call) $Func_DisabledAccounts = Get-ADGroupMember -Identity $global:gbl_SrcGroup -Recursive | ForEach-Object { Get-ADUser $_.SamAccountName -Properties Enabled } | Where-Object { -not $_.Enabled } | Select-Object Name, SamAccountName, distinguishedName
Step 2: Use ObservableCollection for Bulk Binding
WPF's ObservableCollection automatically notifies the UI of changes, so we can load all data into this collection first, then assign it to the DataGrid's ItemsSource in one go (no more manual refreshes!):
# Ensure WPF assemblies are loaded (run once if not already loaded) Add-Type -AssemblyName PresentationFramework # Create an ObservableCollection to hold our data $accountCollection = New-Object System.Collections.ObjectModel.ObservableCollection[PSObject] # Bulk add all items to the collection (this is fast because it doesn't trigger UI updates yet) foreach ($account in $Func_DisabledAccounts) { $accountCollection.Add($account) } # Bind the entire collection to the DataGrid - UI updates once! $DataGrid_DisabledAccounts.ItemsSource = $accountCollection
Why Your Original Approach Was Slow
- Per-item UI updates: Calling
AddChild()+Items.Refresh()in a loop forces the DataGrid to redraw after every single item, which is extremely inefficient for large datasets. - Redundant object creation: You were creating a
$tmpobject and usingAdd-Memberunnecessarily—yourFunc_DisabledAccountsalready contains objects with the exact properties you need. - Incorrect bulk method:
AddChild()is designed for single elements, not collections. SettingItemsSourceis the correct way to bind an entire dataset to a DataGrid.
Bonus: Even Faster Collection Population
If you have a huge dataset, you can use a List<PSObject> first to load all items, then convert it to an ObservableCollection (this avoids the overhead of collection change notifications during population):
$accountList = New-Object System.Collections.Generic.List[PSObject] $accountList.AddRange($Func_DisabledAccounts) $accountCollection = New-Object System.Collections.ObjectModel.ObservableCollection[PSObject]($accountList) $DataGrid_DisabledAccounts.ItemsSource = $accountCollection
内容的提问来源于stack exchange,提问作者Christian Cornelsen

