У меня есть простой список элементов в моем приложении WPF, который я пытаюсь выжать из него. В приведенном ниже коде я добавляю миллион записей и сигнализирую об изменении в моем списке элементов.Как улучшить производительность добавления диапазона в ListView
У меня есть следующий код XAML:
<Window x:Class="Log_.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Log+ Viewer" Height="400" Width="500">
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl>
<TabItem Header="Everything">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding LogRecords}">
<ListView.View>
<GridView>
<GridViewColumn Header="Message" DisplayMemberBinding="{Binding Message}"/>
<GridViewColumn Header="Timestamp" DisplayMemberBinding="{Binding Timestamp}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
Здесь является C# код:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Log_
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableList<LogRecord> LogRecords { get; set; }
public MainWindow()
{
InitializeComponent();
LogRecords = new ObservableList<LogRecord>();
DataContext = this;
new Thread(() =>
{
LogRecord record = new LogRecord();
record.Message = "Hello, world.";
record.Timestamp = DateTime.Now;
List<LogRecord> logRecordList = new List<LogRecord>();
for (int i = 0; i < 1000000; i++)
{
logRecordList.Add(record);
}
Stopwatch timer = new Stopwatch();
timer.Start();
Dispatcher.Invoke(() =>
{
LogRecords.AddRange(logRecordList);
});
timer.Stop();
Console.WriteLine("The operation took {0} milliseconds.", timer.ElapsedMilliseconds);
}).Start();
}
public class LogRecord
{
public string Message { get; set; }
public DateTime Timestamp { get; set; }
}
public class ObservableList<T> : IEnumerable<T>, INotifyCollectionChanged
{
public List<T> UnderlyingList = new List<T>();
public event NotifyCollectionChangedEventHandler CollectionChanged;
public void AddRange(IEnumerable<T> list)
{
UnderlyingList.AddRange(list);
OnCollectionChange(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, UnderlyingList));
}
protected virtual void OnCollectionChange(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
{
CollectionChanged(this, e);
}
}
public IEnumerator<T> GetEnumerator()
{
return UnderlyingList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return UnderlyingList.GetEnumerator();
}
}
}
}
Выход: "Операция прошла 4834 миллисекунды."
Это кажется абсурдным количеством времени для его добавления этих записей в виде ряда записей. Я нарушаю виртуализацию пользовательского интерфейса здесь, потому что источник моих объектов наследует IEnumerable, как это, или это нормальная производительность? Как я могу заставить этот код работать намного быстрее, чем в настоящее время?
Но не в ListView включить виртуализацию пользовательского интерфейса, так что он отображает только записи он должен отображаться по умолчанию, и из-за этого, если он не справится с этим поведением уже, особенно учитывая тот факт, что я только сигнализирую, что он обновляется один раз из-за логики в ObservableList ... если, конечно, не наследует IEnumerable заставляет его сигнализировать несколько раз ...? – Alexandru
Вы включили отложенную прокрутку? ScrollViewer.IsDeferredScrollingEnabled = "True" – jake
Джейк, я нашел решение ... Я думаю, что наследование IEnumerable действительно было плохой идеей ... Я отправлю его сейчас. Пожалуйста, проверьте это, но обратите внимание, что это не имеет ничего общего с ScrollViewer с включенной отсроченной прокруткой. – Alexandru