2011-11-05 155 views
1

我试图找到一个解决异步DataProvider,但到处都绑定到静态类,但我需要动态绑定到不同的对象。DataVirtualization和ListView UI冻结

我试图使用this solution但我的用户界面仍然冻结。任何人都可以解释为什么我会得到这种行为,以及如何使UI活跃。 应用XAML文件:

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

} 

主窗口:

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

我通过设置'ScrollViewer.CanContentScroll'到'FALSE'介绍这个问题。如果设置为“true”,则异步加载按预期工作。 –

回答

1

我发现了一个简单的解决方案。我没有设置DataContext,而是以低优先级手动添加项目。用户界面不会冻结。目标已实现。

foreach (var r in sec.Records) 
{ 
    listView.Dispatcher.Invoke((new Action(delegate() 
    { 
     listView.Items.Add(r); 
    })), DispatcherPriority.SystemIdle); 
}