Wpf 数据虚拟化和ListView UI冻结
我试图找到一个异步数据提供程序的解决方案,但everywhere绑定到一个静态类,但我需要一个到不同对象的动态绑定 我试图使用,但我的用户界面仍然冻结。任何人都可以解释我为什么会有这种行为,以及如何激活UI。 应用程序XAML文件:Wpf 数据虚拟化和ListView UI冻结,wpf,Wpf,我试图找到一个异步数据提供程序的解决方案,但everywhere绑定到一个静态类,但我需要一个到不同对象的动态绑定 我试图使用,但我的用户界面仍然冻结。任何人都可以解释我为什么会有这种行为,以及如何激活UI。 应用程序XAML文件: <Window x:Class="WpfApplication_async.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
<Window x:Class="WpfApplication_async.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication_async"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:RecordValueDataTemplateSelector x:Key="myDataTemplateSelector"/>
<DataTemplate x:Key="ComboBoxTemplate">
<ComboBox Width="{Binding Path=ColumnDef.ColumnWidth,Mode=OneTime}"
ItemsSource="{Binding Path=viewEntityList,Mode=TwoWay}"
SelectedIndex="{Binding Path=Index, Mode=TwoWay}">
</ComboBox>
</DataTemplate>
<DataTemplate x:Key="TextBoxTemplate">
<TextBox Text="{Binding Path=Text,Mode=TwoWay}" Width="{Binding Path=ColumnDef.ColumnWidth,Mode=OneTime}"/>
</DataTemplate>
<DataTemplate x:Key="HeaderTextBlockTemplate">
<TextBlock Width="{Binding Path=ColumnWidth,Mode=OneTime}" Text="{Binding Path=ColumnName,Mode=TwoWay}" ToolTip="{Binding Path=ColumnName}" />
</DataTemplate>
<DataTemplate x:Key="ListBoxTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Key, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" Width="80"/>
<ListBox ItemsSource="{Binding Path=Items}"
ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
<DockPanel>
<ListBox Name="headerListBox" MinHeight="20" DockPanel.Dock="Top"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False"
ItemTemplate="{StaticResource HeaderTextBlockTemplate}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<ScrollViewer Name="listScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Visible">
<ListView Name="listView" SelectionMode="Extended"
VirtualizingStackPanel.IsVirtualizing="True"
ScrollViewer.IsDeferredScrollingEnabled="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource ListBoxTemplate}" >
</ListView>
</ScrollViewer>
</DockPanel>
</ScrollViewer>
<Button Grid.Row="1" Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
</Window>
我的数据提供程序类:
using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Windows.Data;
using System.Windows;
using DataVirtualization;
using System.Threading;
//using System.Threading;
namespace WpfApplication_async
{
public enum MySubKeyValueType { StringValue=0, ListValue=1 }
public class MySection : IItemsProvider<MyRecord>
{
/// <summary>
/// Fetches the total number of items available.
/// </summary>
/// <returns></returns>
public int FetchCount()
{
//Thread.Sleep(1000);
return Records.Count;
}
/// <summary>
/// Fetches a range of items.
/// </summary>
/// <param name="startIndex">The start index.</param>
/// <param name="count">The number of items to fetch.</param>
/// <returns></returns>
public IList<MyRecord> FetchRange(int startIndex, int count)
{
//Thread.Sleep(1000);
if (startIndex > Records.Count) startIndex = Records.Count;
if (startIndex + count > Records.Count) count = Records.Count - startIndex;
return Records.ToList().GetRange(startIndex, count).ToList();
}
public MySection()
{
Records = new ObservableCollection<MyRecord>();
}
public ObservableCollection<MyRecord> Records { get; set;}
}
public class MyRecord : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public MyRecord()
{
Items = new ObservableCollection<MySubKeyValue>();
}
private string key;
public string Key {
get {
return key;
}
set {
//if (Key!=null && this.Parent is MySection && (this.Parent as MySection).SectionDefinition.IsNumberedKeys)
// return;
key = value;
OnPropertyChanged("Key");
}
}
ObservableCollection<MySubKeyValue> items = new ObservableCollection<MySubKeyValue>();
public ObservableCollection<MySubKeyValue> Items
{
get {
return items;
}
set {
items = value;
OnPropertyChanged("NumberedColumnText");
}
}
}
public class MySubKeyValue : DependencyObject, INotifyPropertyChanged
{
private ColumnDefinition columnDef = null;
public ColumnDefinition ColumnDef
{
get
{
if (columnDef == null)
return columnDef = new ColumnDefinition();
return columnDef;
}
set { columnDef = value; }
}
public MySubKeyValue(string str = null)
{
Text = str;
ValueType = MySubKeyValueType.StringValue;
IsValidData = true;
ErrorMessage = "error";
}
private string text;
public MySubKeyValueType ValueType { get; set; }
public string Text
{
get
{
if (text == null) return String.Empty;
return text;
}
set
{
if (text != value)
{
text = value;
OnPropertyChanged("Text");
}
}
}
public bool isValidData = true;
public bool IsValidData
{
get { return isValidData; }
set
{
if (isValidData != value)
{
isValidData = value;
OnPropertyChanged("IsValidData");
}
}
}
public string ErrorMessage { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
public class StringValue : MySubKeyValue
{
public StringValue(string str = null)
{
ValueType = MySubKeyValueType.StringValue;
Text = str;
}
}
public class ListValue : MySubKeyValue
{
private int index;
public int Index
{
get { return index; }
set
{
index = value;
if (index > -1 && index < valueEntityList.Count)
{
base.Text = valueEntityList[index];
IsValidData = true;
}
else
IsValidData = false;
OnPropertyChanged("Index");
}
}
public List<string> valueEntityList { get; set; }
public List<string> viewEntityList { get; set; }
public ListValue(string str, ListValue l)
{
ValueType = MySubKeyValueType.ListValue;
valueEntityList = l.valueEntityList;
viewEntityList = l.viewEntityList;
base.Text = str;
Index = valueEntityList.FindIndex(v => v == str);
}
public ListValue(List<string> _vals = null, List<string> _views = null, string str = "")
{
Index = -1;
ValueType = MySubKeyValueType.ListValue;
valueEntityList = new List<string>();
viewEntityList = new List<string>();
if (_vals != null)
if (_views != null && _views.Count == _vals.Count)
{
valueEntityList.AddRange(_vals);
viewEntityList.AddRange(_views);
}
else
{
valueEntityList.AddRange(_vals);
viewEntityList.AddRange(_vals);
}
base.Text = str;
Index = valueEntityList.FindIndex(v => v == str);
}
}
public class ColumnDefinition : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
public ColumnDefinition(string name = "", int width = 80)
{
ColumnName = name;
ColumnWidth = width;
}
public string ColumnName { get; set; }
private int columnWidth;
public int ColumnWidth
{
get { return columnWidth; }
set { columnWidth = value; OnPropertyChanged("ColumnWidth"); }
}
}
}
使用系统;
使用系统组件模型;
使用System.Collections.ObjectModel;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Text.RegularExpressions;
使用System.Collections.Specialized;
使用System.Windows.Data;
使用System.Windows;
使用数据虚拟化;
使用系统线程;
//使用系统线程;
命名空间WpfApplication\u异步
{
公共枚举MySubKeyValueType{StringValue=0,ListValue=1}
公共类MySection:IItemsProvider
{
///
///获取可用项目的总数。
///
///
公共整数FetchCount()
{
//睡眠(1000);
返回记录。计数;
}
///
///获取一系列项目。
///
///开始索引。
///要获取的项目数。
///
公共IList FetchRange(int startIndex,int count)
{
//睡眠(1000);
如果(startIndex>Records.Count)startIndex=Records.Count;
如果(startIndex+count>Records.count)count=Records.count-startIndex;
return Records.ToList().GetRange(startIndex,count).ToList();
}
公共部门()
{
记录=新的ObservableCollection();
}
公共可观察收集记录{get;set;}
}
公共类MyRecord:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
受保护的void OnPropertyChanged(字符串信息)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新属性ChangedEventArgs(信息));
}
}
公共档案()
{
Items=新的ObservableCollection();
}
私钥;
公共字符串密钥{
获取{
返回键;
}
设置{
//if(Key!=null&&this.Parent为MySection&(this.Parent为MySection.SectionDefinition.IsNumberedKeys)
//返回;
键=值;
已更改的不动产(“密钥”);
}
}
ObservableCollection items=新的ObservableCollection();
公共可观测收集项目
{
得到{
退货项目;
}
设置{
项目=价值;
OnPropertyChanged(“NumberedColumnText”);
}
}
}
公共类MySubKeyValue:DependencyObject,INotifyPropertyChanged
{
private ColumnDefinition columnDef=null;
公共列定义列定义
{
得到
{
if(columnDef==null)
return columnDef=new ColumnDefinition();
返回列def;
}
设置{columnDef=value;}
}
public MySubKeyValue(字符串str=null)
{
Text=str;
ValueType=MySubKeyValueType.StringValue;
IsValidData=true;
ErrorMessage=“error”;
}
私有字符串文本;
public MySubKeyValueType ValueType{get;set;}
公共字符串文本
{
得到
{
if(text==null)返回String.Empty;
返回文本;
}
设置
{
如果(文本!=值)
{
文本=值;
OnPropertyChanged(“文本”);
}
}
}
公共bool isValidData=true;
公共布尔伊斯瓦利达酒店
{
获取{return isValidData;}
设置
{
如果(isValidData!=值)
{
isValidData=值;
OnPropertyChanged(“IsValidData”);
}
}
}
公共字符串错误消息{get;set;}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串信息)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新属性ChangedEventArgs(信息));
}
}
}
公共类StringValue:MySubKeyValue
{
公共字符串值(字符串str=null)
{
ValueType=MySubKeyValueType.StringValue;
Text=str;
}
}
公共类ListValue:MySubKeyValue
{
私有整数索引;
公共整数索引
{
获取{返回索引;}
设置
{
指数=价值;
如果(索引>-1&&indexv==str);
}
public ListValue(列表_vals=null,列表_views=null,字符串str=”“)
{
指数=-1;
ValueType=MySubKeyValueType.ListValue;
valueEntityList=新列表();
viewEntityList=新列表();
如果(_vals!=null)
如果(_views!=null&&&u views.Count==_vals.Count)
{
valueEntityList.AddRange(\u vals);
viewEntityList.AddRange(_视图);
}
其他的
{
valueEntityList.AddRange(\u vals);
viewEntityList.AddRange(_vals);
}
base.Text=str;
Index=valueEntityList.Fi
namespace WpfApplication_async
{
public partial class MainWindow : Window
{
MySection sec1,sec2;
bool isSec1 = true;
public MainWindow()
{
InitializeComponent();
sec1 = new MySection();
for(int i=0;i<50;i++){
MyRecord rec = new MyRecord();
rec.Key = i.ToString();
for(int j=0;j<20;j++){
rec.Items.Add(new StringValue("abc"));
rec.Items[rec.Items.Count - 1].ColumnDef = new ColumnDefinition(j.ToString());
}
sec1.Records.Add(rec);
}
sec2 = new MySection();
for (int i = 0; i < 50; i++)
{
MyRecord rec = new MyRecord();
rec.Key = i.ToString();
for (int j = 0; j < 20; j++)
{
rec.Items.Add(new ListValue(new List<string> { "a", "b" }, new List<string> { "a", "b" }, "a"));
rec.Items[rec.Items.Count - 1].ColumnDef = new ColumnDefinition(j.ToString());
}
sec2.Records.Add(rec);
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (isSec1)
//listView.DataContext = sec2;
listView.DataContext = new AsyncVirtualizingCollection<MyRecord>(sec2, 10, 30 * 1000);
else
//listView.DataContext = sec1;
listView.DataContext = new AsyncVirtualizingCollection<MyRecord>(sec1, 10, 30 * 1000);
isSec1 = !isSec1;
}
}
}
foreach (var r in sec.Records)
{
listView.Dispatcher.Invoke((new Action(delegate()
{
listView.Items.Add(r);
})), DispatcherPriority.SystemIdle);
}