gpt4 book ai didi

c# - 如何提高 WPF 中列表框的绑定(bind)更新性能?

转载 作者:行者123 更新时间:2023-11-30 22:42:29 26 4
gpt4 key购买 nike

场景是这样的,我有一个操作可以清除 ObservableCollection,运行查询,然后用查询结果重新填充集合。该集合通过列表框进行数据绑定(bind)。这是踢球者,500 个查询结果会导致一些严重的更新时间,这会阻止用户界面被认为“太长”(实际上在大多数系统上是 .5-2 秒)无论哪种方式,我知道查询足够快,就像添加元素一样,所以我将它缩小到表示层。

做一些测试,如果我从列表框中删除项目模板,我会得到明显更好的性能(duh),但不会好到它甚至可以满足传达给我的期望。我将绑定(bind)更新为适用的一种方式,我将虚拟化模式更改为回收,并确保我使用的是静态资源,以上都没有对重新绘制产生明显影响。我想知道是否还有其他人知道如何提高填充了大量项目的列表框的性能?

<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>

因为它在下面被问过几次,不,这不是我的可观察集合......我通过进行一批更新并将项目源重新分配给新实例来抑制事件。

    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;
}

最佳答案

如果您想显示(您的查询的)结果恰好是大量数据,那么我建议您将 DataPager 与 DataGrid/ListView/ListBox 一起使用,并且只显示与可用空间一样多的项目可以容纳(不创建垂直滚动条)。为此,您必须编写一个 DataPager 控件,因为它没有随 WPF 一起提供(尽管 Silverlight 有 DataPager!)。 (我为我的项目编写了 DataPager 来解决类似的问题。编写自己的控件很有趣!)

但即使在那之前你也可以试试这个:(它可能有效)

<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>

取而代之的是:

<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>

您可能还想看看这些文章:

Data virtualization
UI Virtualization
How can I filter data virtualized items in WPF?
How can I sort data virtualized items in WPF?

编辑:因为当您填充 resultCollection 时,每个 Add() 都会触发一个集合更改事件,该事件由您的 WPF 控件处理。所以这不是一个好主意,因为如果有 1000 个项目要添加到您的 resultCollection,那么您的代码(或 WPF 控件)将处理 1000 个事件。那是不必要的。因此,您可以按照 Marijn 的建议抑制此事件。

但是我建议你使用这个技巧来抑制不必要的事件:

ObservableCollection<Result> temp = resultCollection;
resultCollection = null ; // make it null so it will not fire any event anymore to be handled by wpf!
temp.clear()

foreach(/*your code*/)
{
temp.Add(item); //since temp is not bound to any control, temp's collection changed event will not be handled by anyone! Means, No Handler, No Code to Execute, No time waste!
}

resultCollection = temp ; //this fires event, which is handled by your code/ wpf.

关于c# - 如何提高 WPF 中列表框的绑定(bind)更新性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4402752/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com