Also hier ist das Szenario, ich habe eine Operation, die eine ObservableCollection löscht, führt eine Abfrage, und füllt die Sammlung mit den Abfrageergebnissen. Diese Sammlung ist databound zu durch eine Listbox. Hier ist der Kicker, 500 Abfrageergebnisse verursacht einige ernsthafte Update-Zeit, die die Benutzeroberfläche für das, was als "zu lange" (in Wirklichkeit ist es .5-2 Sekunden auf den meisten Systemen) wahrgenommen wird blockiert.
Wenn ich einige Tests durchführe, erhalte ich eine deutlich bessere Leistung, wenn ich die Elementvorlage aus der Listbox entferne (duh), aber nicht so viel besser, dass sie sogar die Erwartungen erfüllen würde, die mir mitgeteilt wurden. Ich habe die Bindungen so aktualisiert, dass sie nur in einer Richtung funktionieren, ich habe den Virtualisierungsmodus auf Recycling umgestellt und ich habe sichergestellt, dass ich statische Ressourcen verwende, aber keine der oben genannten Maßnahmen hatte einen spürbaren Einfluss auf das erneute Zeichnen. Ich habe mich gefragt, ob jemand eine gute Idee hat, wie man die Leistung einer Listbox verbessern kann, die mit großen Mengen von Elementen gefüllt ist?
<ListBox x:Name="listBox" Grid.Row="1" Grid.ColumnSpan="5" ItemsSource="{Binding SerialResults}" ItemTemplate="{StaticResource UnitHistoryTemplate}" BorderThickness="2" Grid.IsSharedSizeScope="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<DataTemplate x:Key="UnitHistoryTemplate">
<DataTemplate.Resources>
<DataTemplate x:Key="UnitFailureItemTemplate">
<Grid>
<TextBlock Margin="4,0,4,0" TextWrapping="Wrap" Text="{Binding}" Foreground="Red"/>
</Grid>
</DataTemplate>
</DataTemplate.Resources>
<Grid d:DesignWidth="580" d:DesignHeight="30" Background="#00000000">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="load"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="run"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="ser"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="mot"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="result"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Load" Text="{Binding Load.LoadNumber, Mode=OneTime}" Margin="4,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" d:LayoutOverrides="HorizontalAlignment"/>
<TextBlock x:Name="Run" Text="{Binding Run.RunNumber, Mode=OneTime}" Margin="4,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" d:LayoutOverrides="HorizontalAlignment" Grid.Column="1"/>
<TextBlock x:Name="Serial" Text="{Binding Unit.SerialNumber, Mode=OneTime}" Margin="4,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" d:LayoutOverrides="HorizontalAlignment" Grid.Column="2"/>
<TextBlock x:Name="Mot" Text="{Binding Unit.MotString, Mode=OneTime}" Margin="4,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" d:LayoutOverrides="HorizontalAlignment" Grid.Column="3"/>
<TextBlock x:Name="Result" Text="{Binding Run.Result, Mode=OneTime}" Margin="4,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="4" d:LayoutOverrides="HorizontalAlignment, GridBox"/>
<ItemsControl ItemsSource="{Binding Unit.Failed, Mode=OneTime}" ItemTemplate="{StaticResource UnitFailureItemTemplate}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="5">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Run.Result, Mode=OneTime}" Value="Aborted">
<DataTrigger.Setters>
<Setter TargetName="Result" Property="Foreground" Value="Red"/>
</DataTrigger.Setters>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Und da es über ein paar Mal unten gefragt wurde, nein, es ist nicht meine beobachtbare Sammlung... Ich unterdrücke das Ereignis, indem ich einen Stapel von Updates und neu zuweisen die Elemente Quelle zu einer neuen Instanz.
public async void FindUnitHistory()
{
if (IsCaching)
{
return;
}
else if (_serialSearch.Length <= MIN_SEARCH_LENGTH)
{
SerialResults.Clear();
return;
}
var newData = new ObservableCollection<UnitHistory>();
await TaskEx.Run(() =>
{
var results = from load in cache.LoadData.AsParallel()
from run in load.Runs
from unit in run.Units
where unit.SerialNumber.StartsWith(_serialSearch)
orderby run.RunNumber ascending
orderby load.LoadNumber descending
select new UnitHistory(load, run, unit);
foreach (var p in results)
{
newData.Add(p);
}
});
SerialResults = newData;
}