C# 使用VirtualzingPanel在一个巨大的列表框中滚动。ScrollUnit=";像素“;
在WPF4.5中,我在列表框中显示一个相当长的列表时遇到了一些速度问题:我的列表框包含大约5000个项目,这些项目可能有不同的高度。每个项目都显示通过查询检索的信息,该查询在项目显示后立即执行。这种延迟的查询执行是必要的,因为一次对所有内容执行此操作将花费太多时间。我通过将ItemsControl绑定到首次访问项中的属性时创建的对象来完成延迟查询 例如:C# 使用VirtualzingPanel在一个巨大的列表框中滚动。ScrollUnit=";像素“;,c#,wpf,data-binding,listbox,ui-virtualization,C#,Wpf,Data Binding,Listbox,Ui Virtualization,在WPF4.5中,我在列表框中显示一个相当长的列表时遇到了一些速度问题:我的列表框包含大约5000个项目,这些项目可能有不同的高度。每个项目都显示通过查询检索的信息,该查询在项目显示后立即执行。这种延迟的查询执行是必要的,因为一次对所有内容执行此操作将花费太多时间。我通过将ItemsControl绑定到首次访问项中的属性时创建的对象来完成延迟查询 例如: public class ItemViewModel { public NotifyTaskCompletion<Observa
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会呈现当前滚动位置上方的所有项目,这需要很长时间,因为所有查询和查询数据的复杂呈现
如果我设置virtualzingpanel.ScrollUnit=“Unit”,我没有任何速度问题。列表框仅显示滚动到的项目,因此仅显示查询的信息。不幸的是,我需要使用“像素”设置,因为我的项目有时太大,我需要滚动像素以确保用户可以看到所有项目
我知道最好有一个查询队列,以避免同时启动数百个线程,但我认为这不会改变ListBox呈现我不想显示的项目这一基本问题
我真的不知道如何解决这个问题。有人能帮我吗?已推迟滚动并在ListBoxItem中滚动
<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; }
}
公共部分类主窗口:窗口
{
私有列表deferedItems=新列表();
公共主窗口()
{
this.DataContext=this;
对于(int32i=0;i<100000;i++)deferedItems.Add(newdefereditem(i));
初始化组件();
}
公共列表延迟项{获取{返回延迟项;}}
}
公共类
{
私有Int32 id;
私有日期时间?dt=null;
私有列表defStrings=新列表();
公共日期时间
{
得到
{
如果(dt==null)
{
系统线程线程睡眠(1000);
dt=日期时间。现在;
}
返回(日期时间)dt;
}
}
公共列表字符串
{
得到
{
如果(defStrings.Count==0)
{
对于(Int32 i=id;i
为什么不在ListBoxItem中放置一个最大高度的ListBox?并打开延迟滚动。谢谢,这当然是一个选项!我不知道延迟滚动。拥有两个嵌套的ScrollViewer可能不是最好的选择,但现在我很高兴它能与您的想法配合使用!:)
<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; }
}