Низкая производительность при фильтрации ICollectionView <object> - PullRequest
0 голосов
/ 08 октября 2018

В приложении WPF с использованием MVVM я запрашиваю базу данных, чтобы получить ObservableCollection клиентов, создаю ICollectionView и применяю функцию фильтра.

В моем пользовательском контроле я связываю текст, используемый для фильтра, с текстовым полем иICollectionView to Listbox.

ICollectionView изначально содержит 1104 клиента (только ClientID и ClientName).

Извлечение данных из базы данных происходит очень быстро.Однако заполнение списка занимает около 4 секунд.

Когда я ввожу текст в фильтр, если количество возвращаемых клиентов невелико, тогда список перерисовывается относительно быстро.Однако, если я очищаю текстовое поле, тогда еще 4 секунды перерисовываются.

Я что-то упустил или мой код написан не очень хорошо.

Спасибо за любой совет / помощь.

Просмотр:

<UserControl x:Class="ClientReports.Module.SchemeSelection.Views.Clients"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:ClientReports.Module.SchemeSelection.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True" >
    <Grid>
        <StackPanel>
            <TextBox  materialDesign:HintAssist.Hint="Client Search"
                      Style="{StaticResource MaterialDesignFloatingHintTextBox}"
                      Text="{Binding Search, UpdateSourceTrigger=PropertyChanged}"/>
            <ListBox ItemsSource="{Binding ClientsFiltered}" DisplayMemberPath="ClientName" />
        </StackPanel>
    </Grid>
</UserControl>

ViewModel:

using ClientReports.Common.Infrastructure.Models;
using ClientReports.Common.Infrastructure.Services;
using Prism.Mvvm;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Data;

namespace ClientReports.Module.SchemeSelection.ViewModels
{
    public class ClientsViewModel : BindableBase
    {
        private IClientService clientService;

        public ClientsViewModel(){ }

        public ClientsViewModel(IClientService clientService)
        {
            this.clientService = clientService;
            Clients = new ObservableCollection<Client>();
            GetClients().ContinueWith(x => { });
        }

        public ObservableCollection<Client> Clients { get; }

        public ICollectionView ClientsFiltered { get; set; }

        private string clientFilter;

        public string Search
        {
            get => clientFilter;
            set
            {
                clientFilter = value;
                ClientsFiltered.Refresh();
                RaisePropertyChanged("ClientsFiltered");
            }
        }

        private bool Filter(Client client)
        {
            return Search == null
                || client.ClientName.IndexOf(Search, StringComparison.OrdinalIgnoreCase) != -1;
        }


        private async Task GetClients()
        {
            var clients = await clientService.GetAllAsync();
            foreach (var client in clients)
            {
                Clients.Add(client);
            }
            ClientsFiltered = CollectionViewSource.GetDefaultView(Clients);
            ClientsFiltered.Filter = new Predicate<object>(c => Filter(c as Client));
        }
    }
}

1 Ответ

0 голосов
/ 08 октября 2018

ListBox, вероятно, занимает 4 секунды для заполнения, потому что виртуализация не включена, поэтому WPF должен создать 1104 ListBoxItems (и воссоздать их, когда фильтр очищен).По умолчанию виртуализация включена для ListBox, но вы можете иногда отключать ее, даже не осознавая этого.В вашем примере ваш ListBox расположен в вертикальной StackPanel, и это, вероятно, причина для такого поведения.Вы можете попробовать переписать XAML следующим образом:

<UserControl x:Class="ClientReports.Module.SchemeSelection.Views.Clients"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:ClientReports.Module.SchemeSelection.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             xmlns:prism="http://prismlibrary.com/"
             prism:ViewModelLocator.AutoWireViewModel="True" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

            <TextBox  materialDesign:HintAssist.Hint="Client Search"
                      Style="{StaticResource MaterialDesignFloatingHintTextBox}"
                      Text="{Binding Search, UpdateSourceTrigger=PropertyChanged}"
                      Grid.Row="0"/>
            <ListBox  ItemsSource="{Binding ClientsFiltered}"  
                      DisplayMemberPath="ClientName"
                      Grid.Row="1" />            
    </Grid>
</UserControl>

Если это не поможет, вы можете попробовать установить фиксированную высоту для вашего ListBox и проверить его снова.

Если этоТакже не помогает, пожалуйста, проверьте документацию Microsoft по виртуализации по другим возможным причинам: https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/optimizing-performance-controls

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...