我在WPF 4.5中的ListBox中显示一个相当长的列表有一些速度问题:我的ListBox包含大约5000个项目,并且项目可以具有不同的高度。每个项目显示通过显示项目后立即执行的查询检索的信息。这种延迟的查询执行是必要的,因为一次为所有内容执行此操作将花费太多时间。我已经通过将ItemsControl绑定到首次访问项目中的Property时创建的NotifyTaskCompletion对象来完成delaye查询。
例如:
public class ItemViewModel
{
public NotifyTaskCompletion<ObservableCollection<Content>> QueryResult
{
get
{
if(_queryTask == null)
{
_queryTask = new NotifyTaskCompletion<ObservableCollection<Content>>
(Task<ObservableCollection<Content>>.Run(queryFunction));
}
return _queryTask;
}
}
}
ItemTemplate:
+--------------------------------------------------+
| TextBlock with header |
| |
| ItemsControl Source={Binding QueryResult.Result} |
+--------------------------------------------------+
因此,每次显示一个项目时,它都会启动一个执行查询的线程,并在查询完成后显示内容。通过查询检索的信息可能非常多,这意味着ListBox中的项可能比ListBox本身大。这就是我需要在ListBox中设置VirtualizingPanel.ScrollUnit =“Pixel”以确保用户可以看到整个项目的原因。
+-------------------------------------------+
| ListBox, too small for big Item 1 |
| |
| +------------------------------+ |
| | Header 1 | |
| | | |
| | Lot's of information ....... | |
| | Lot's of information ....... | |
| | Lot's of information ....... | |
| | Lot's of information ....... | |
+-| Lot's of information ....... |----------+
| Lot's of information ....... |
| Lot's of information ....... |
| Lot's of information ....... |
+------------------------------+
+------------------------------+
| Header 2 |
| |
| Not so much information..... |
+------------------------------+
但是,这会大大减慢滚动速度。如果我将滚动条中的拇指拖动到列表中间,则会冻结几秒钟,之后会显示一些项目而不显示查询信息。然后,一些项目显示查询的信息。然后ListBox似乎跳转到另一个位置,这又导致另一个冻结,依此类推。看起来ListBox呈现的是当前滚动位置之上的所有项目,由于所有查询和查询数据的复杂呈现,这需要很长时间。
如果我设置VirtualizingPanel.ScrollUnit =“Unit”,我没有任何速度问题。 ListBox仅显示滚动到的项目,因此仅显示查询的信息。不幸的是,我需要使用“像素”设置,因为我的项目有时太大,我需要像素滚动,以确保用户可以看到所有这些。
我知道最好有一个查询队列,以避免一次启动数百个线程,但我认为这不会改变ListBox呈现的基本问题。我不会显示的项目。
我不确定如何解决这个问题。任何人都可以帮助我吗?
答案 0 :(得分:0)
延迟滚动并滚动列表框项目
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Path=DeferedItems}"
ScrollViewer.IsDeferredScrollingEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
VirtualizingStackPanel.VirtualizationMode="Standard">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=ID}"/>
<ListBox ItemsSource="{Binding Path=DefStrings}" Margin="10,0,0,0"
MaxHeight="300"
ScrollViewer.VerticalScrollBarVisibility="Visible"/>
<TextBlock Text="{Binding Path=DT}" Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
public partial class MainWindow : Window
{
private List<DeferedItem> deferedItems = new List<DeferedItem>();
public MainWindow()
{
this.DataContext = this;
for (Int32 i = 0; i < 100000; i++) deferedItems.Add(new DeferedItem(i));
InitializeComponent();
}
public List<DeferedItem> DeferedItems { get { return deferedItems; } }
}
public class DeferedItem
{
private Int32 id;
private DateTime? dt = null;
private List<String> defStrings = new List<string>();
public DateTime DT
{
get
{
if (dt == null)
{
System.Threading.Thread.Sleep(1000);
dt = DateTime.Now;
}
return (DateTime)dt;
}
}
public List<String> DefStrings
{
get
{
if (defStrings.Count == 0)
{
for (Int32 i = id; i < id + 1000; i++) defStrings.Add(i.ToString() + " " + DateTime.Now.ToLongTimeString());
}
return defStrings;
}
}
public Int32 ID { get { return id; } }
public DeferedItem(Int32 ID) { id = ID; }
}