2016-06-29 6 views
0

В настоящее время я отчаиваюсь от моего опыта работы с графическим интерфейсом C# WPF. Im тихий новичок в WPF и привязки данных, а также не им нет C# эксперта ...Проблема с эффективностью привязки данных при загрузке огромных списков

Я попробовал демо-шаблон для основного MVVM WPF Шаблон: https://msdn.microsoft.com/en-us/magazine/dd419663.aspx

... и добавил ~ 2000 клиента проверить поведение gui в огромных списках данных, потому что мне приходится иметь дело с огромными списками сложных данных в моем личном проекте.

Поскольку отображение списка клиентов происходит в WPF-Data-Binding-Magic, неуверенность в том, как сохранить контроль времени загрузки графического интерфейса (до 12 секунд с данными +2000).

CustomerRepository:

readonly List<Customer> _customers; 

/// <summary> 
/// Returns a shallow-copied list of all customers in the repository. 
/// </summary> 
public List<Customer> GetCustomers() 
{ 
    return new List<Customer>(_customers); 
} 

AllCustomerView.xaml/ListView, который содержит список клиентов:

<ListView 
    AlternationCount="2" 
    DataContext="{StaticResource CustomerGroups}" 
    ItemContainerStyle="{StaticResource CustomerItemStyle}" 
    ItemsSource="{Binding}" 
    > 
    <ListView.GroupStyle> 
    <StaticResourceExtension 
     ResourceKey="CustomerGroupStyle" 
     /> 
    </ListView.GroupStyle> 

    <ListView.View> 
    <GridView> 
     <GridViewColumn 
     Header="Name" 
     DisplayMemberBinding="{Binding Path=DisplayName}" 
     /> 
     <GridViewColumn 
     Header="E-mail" 
     DisplayMemberBinding="{Binding Path=Email}" 
     /> 
     <GridViewColumn Header="Total Sales"> 
     <GridViewColumn.CellTemplate> 
      <DataTemplate> 
      <ContentPresenter 
       Content="{Binding Path=TotalSales}" 
       ContentStringFormat="c" 
       HorizontalAlignment="Right" 
       /> 
      </DataTemplate> 
     </GridViewColumn.CellTemplate> 
     </GridViewColumn> 
    </GridView> 
    </ListView.View> 
</ListView> 



<UserControl.Resources> 
<CollectionViewSource 
    x:Key="CustomerGroups" 
    Source="{Binding Path=AllCustomers}" 
    > 
    <CollectionViewSource.GroupDescriptions> 
    <PropertyGroupDescription PropertyName="IsCompany" /> 
    </CollectionViewSource.GroupDescriptions> 
    <CollectionViewSource.SortDescriptions> 
    <!-- 
    Sort descending by IsCompany so that the 'True' values appear first, 
    which means that companies will always be listed before people. 
    --> 
    <scm:SortDescription PropertyName="IsCompany" Direction="Descending" /> 
    <scm:SortDescription PropertyName="DisplayName" Direction="Ascending" /> 
    </CollectionViewSource.SortDescriptions> 
</CollectionViewSource> 

Мой вопрос:

  1. Есть ли способ я могу assync. загружать данные, не замораживая gui во время загрузки списка?

  2. Есть ли способ отслеживать прогресс или даже обрабатывать уже отображаемые данные до тех пор, пока все предметы не будут загружены правильно?

  3. Плюс: Я борется с привязкой данных между методом GetCustomers() и XAML-Bindings. Где «реальная связь» между этими двумя сторонами?

+0

Используйте один из способов связывания, –

ответ

0

В следующем упрощенном примере связывает ListView к модели представления с асинхронным LoadCustomers методом.

Customer экземпляры создаются в отдельном потоке (по Task.Run()) и добавляют к ObservableCollection через Dispatcher вызова (потому что коллекция должна быть изменена только в потоке пользовательского интерфейса).

в LoadCustomers выполняется в Loaded обработчика событий окна, так как оно должно быть await ed, что невозможно сделать в конструкторе MainWindow.

<ListView ItemsSource="{Binding Customers}"> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}"/> 
     </GridView> 
    </ListView.View> 
</ListView> 

код позади:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     var viewModel = new ViewModel(); 
     DataContext = viewModel; 

     Loaded += async (s, e) => await viewModel.LoadCustomers(); 
    } 
} 

public class Customer 
{ 
    public string Name { get; set; } 
} 

public class ViewModel 
{ 
    public ObservableCollection<Customer> Customers { get; private set; } 
     = new ObservableCollection<Customer>(); 

    public async Task LoadCustomers() 
    { 
     await Task.Run(() => 
     { 
      for (int i = 0; i < 2000; i++) 
      { 
       var customer = new Customer 
       { 
        Name = string.Format("Customer {0}", i + 1) 
       }; 

       Application.Current.Dispatcher.Invoke(() => Customers.Add(customer)); 
      } 
     }); 
    } 
} 
+0

Ну, спасибо, но так как я использую MVVM-шаблон я не могу получить доступ к " Loaded 'в модели Customer-ViewModel, на самом деле я никак не могу получить доступ к окну. – Sweeed

+0

@Sweeed, вы можете загрузить метод в vm и загрузить его из самого конструктора – Eldho

+1

Ну, это MVVM. Не требуется *, чтобы обработчик Loaded Event вызывал LoadCustomers (но только пример). Вы могли бы также называть его везде, где вам нравится, в вашей модели просмотра. – Clemens

0

Я хотел бы сделать это таким образом

public class ViewModel : INotifyPropertyChanged 
{ 
    public ViewModel() 
    { 
     ... 
     LoadCostumersAsync(); //code after this line executes before LoadCostumersAsync() is finished, so your UI remains responsive 
     ... 
    } 

    private ObservableCollection<Customer> _customers; 
    public ObservableCollection<Customer> Customers { get { return _customers; } } 

    private async void LoadStopsAsync() 
    { 
     IsLoading= true; // you can use this property to show a busyindicator on the UI 

     _customers = await LoadCostumers; 

     IsLoading = false; 
    } 

    public System.Threading.Tasks.Task<ObservableCollection<Customer>> LoadCostumers() 
    { 
     return System.Threading.Tasks.Task.Factory.StartNew(() => 
     { 
      return YourMethodThatGetsCostumers(); 
     }); 
    } 
} 
Смежные вопросы