Улучшение производительности связывания в WPF? - PullRequest
1 голос
/ 31 июля 2010

Я понимаю, что этот вопрос можно свести к "Почему мой код такой медленный?" но я надеюсь получить больше от этого. Позвольте мне объяснить мой код.

У меня есть класс, который реализует INotifyPropertyChanged для выполнения привязки, и этот класс выглядит примерно так:

  public class Employee : INotifyPropertyChanged 
    { 
        string m_strName = "";
        string m_strPicturePath = "";
        public event PropertyChangedEventHandler PropertyChanged;

        public string Picture
        {
            get { return this.m_strPicturePath; }
            set { this.m_strPicturePath = value; 
            NotifyPropertyChanged("Picture"); }
        }

        public string Name
        {
            get { return this.m_strName; }
            set { this.m_strName = value;
            NotifyPropertyChanged("Name");
            }
        }

        private void NotifyPropertyChanged(String pPropName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(pPropName));
            }
        }
    }

В моем XAML я создал DataTemplate, который привязывается к этому объекту:

 <DataTemplate x:Key="EmployeeTemplate">
        <Border Height="45" CornerRadius="0" BorderBrush="Gray" BorderThickness="0" Background="Transparent" x:Name="bordItem">
            <Grid Width="Auto">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Path=Name}" VerticalAlignment="Center" Padding="10" HorizontalAlignment="Stretch" FontWeight="Bold" FontSize="20"/>
                <Image Grid.Column="1" Source="{Binding Path=Picture}"></Image>
            </Grid>
        </Border>
    </DataTemplate>

и затем поместите этот шаблон в ListBox:

<ListBox x:Name="lstEmployees" ItemTemplate="{DynamicResource EmployeeTemplate}" VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.IsVirtualizing="True"></ListBox>

Таким образом, в коде это установлено как:

lstEmployees.ItemsSource = this.m_Employees;

список "m_Employees" гидратируется при запуске приложения из базы данных, а затем, после этого, я устанавливаю приведенную выше строку кода. ListBox находится на TabControl.

Теперь моя актуальная проблема: мой список «m_Employees» возвращает около 500+ сотрудников из базы данных, поэтому коллекция немного велика. Я получаю снижение производительности только в WPF , когда приложение запускается впервые, и кто-то переходит на эту вкладку со списком ListBox. Пользовательский интерфейс останавливается примерно на 3 секунды, но только при первом запуске приложения - после этого все нормально.

Может ли это быть потому, что:

  • Код должен попасть на жесткий диск, чтобы найти изображение каждого сотрудника?
  • Я занимаюсь виртуализацией неправильно?
  • EDIT
  • WPF выполняет рендеринг с использованием моего DataTemplate один раз, только когда кто-то переходит на этот TabControl, и вдруг пытается нарисовать более 500 элементов сотрудника? Если так, есть ли способ «предварительно загрузить» ListView в WPF?

Буду признателен за любые другие предложения по улучшению вышеизложенного. Спасибо за чтение и за любые советы заранее.

-R.

Ответы [ 2 ]

8 голосов
/ 02 августа 2010
  1. Оберните m_Employees общедоступным свойством (Сотрудники)
  2. Вместо установки вашего ItemsSource в коде, как вы делаете, установите его для Binding и установите IsAsync в True.

ItemsSource = "{Binding Empolyess, IsAsync = True }"

Вы также можете назначить привязку в коде.

Надеюсь, что этопомогает.

0 голосов
/ 31 июля 2010

Качество вашего запроса определенно подозрительно.Если вы хотите, чтобы он работал лучше, вы можете использовать любое количество ленивых методов инициализации, чтобы заставить его работать быстрее.

Самый простой вариант - начать с пустого перечисления и заполнить его только позднее..

Очевидный способ сделать это - добавить кнопку «Запрос» или «Обновить» и заморозить приложение только тогда, когда пользователь щелкнет по нему.

Другой простой вариант -поставьте в очередь фоновое задание / поток, чтобы выполнить обновление.

Если вас больше беспокоит согласованный интерфейс perf / super-отзывчивый пользовательский интерфейс, вам следует попытаться выполнить более детальные запросы.

Я не являюськонечно, если WPF обрабатывает виртуализацию элементов (извлекает только из перечисления, когда появляется каждый элемент), но если это так, вы можете выполнить возврат на страницы / yield для подачи ItemsSource.

Если WPF просто захватывает всеПеречисление за раз, вы все равно можете сделать меньший lazy-eval / paging, если вы можете определить, какие элементы отображаются.Просто заполните объект "зомби" элементами, и, когда они появятся, выполните запрос и обновите свойства отдельного элемента.

...