Region или ItemsSource для большого набора данных в ListBox
У меня проблемы с выяснением того, какое лучшее решение дается в следующей ситуации. Я использую Prism 4.1, MEF и.Net 4.0.
У меня есть объект Project
которые могут иметь большое количество (~1000) Line
объекты. Я решаю, лучше ли выставить ObservableCollection<LineViewModel>
от моего ProjectViewModel
и вручную создайте там видовые модели Line ИЛИ установите ListBox в качестве своего собственного региона и активируйте представления таким образом.
Я все еще хотел бы мой LineViewModel
сделать инъекцию общих служб Prism (IEventAggregator и т. д.), но я не знаю, как это сделать, когда я вручную создаю LineViewModel
, Есть предложения или мысли?
РЕДАКТИРОВАТЬ: Мои первые мысли:
Проект:
public class Project
{
public List<Line> Lines { get; set; }
}
ProjectViewModel:
[Export(typeof(ProjectViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ProjectViewModel : NotificationObject, IRegionMemberLifetime
{
private Project _localProject;
/*
HERE WILL BE SOME PROPERTIES LIKE COST, PRICE THAT ARE CUMULATIVE FROM THE Lines
*/
public ObservableCollection<LineViewModel> Lines { get; private set; }
private readonly IEventAggregator _eventAggregator;
[ImportingConstructor]
public ProjectViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<ProjectLoaded>().Subscribe(SetupProject, false);
Lines = new ObservableCollection<LineViewModel>();
}
private void SetupProject(Project project)
{
_localProject = project;
foreach(var l in _localProject.Lines)
{
LineViewModel lvm = new LineViewModel(l);
lvm.PropertyChanged += // Some handler here
Lines.Add(lvm);
}
}
public bool KeepAlive
{
get { return false; }
}
}
LineViewModel:
public class LineViewModel : NotificationObject
{
private Line _localLine;
public decimal Cost
{
get { return _localLine.Cost; }
set
{
_localLine.Cost = value;
RaisePropertyChanged(() => Cost);
}
}
public LineViewModel(Line incoming)
{
_localLine = incoming;
}
}
2 ответа
Я мог бы быть далеко от базы, может быть, это слишком просто, но поможет ли это вам вообще? Я создал быстрый проект, который продемонстрировал несколько основ. Если вам нужна дополнительная информация, может быть, я могу использовать ее, чтобы помочь вам больше.
Пример приложения с привязкой к "линиям"
Посмотреть
<Window x:Class="WpfApplication1.LinesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LinesView" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="247" d:DesignWidth="348" SizeToContent="WidthAndHeight" Width="350" Height="250">
<Window.Resources>
<DataTemplate x:Key="LineView">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto" MinWidth="50"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Line: " />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="X: " />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding X}" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Y: " />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Y}" />
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="Total Cost" Margin="5" />
<TextBlock Text="{Binding Cost}" Margin="5" />
</StackPanel>
<ContentControl Name="contentControl1" Content="{Binding ElementName=listBox1, Path=SelectedItem}" ContentTemplate="{StaticResource LineView}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="105" Margin="5" />
<ListBox Height="234"
HorizontalAlignment="Center"
Name="listBox1"
VerticalAlignment="Center"
ItemsSource="{Binding Lines}"
ItemTemplate="{StaticResource LineView}" Width="152" Margin="5" />
</StackPanel>
</Window>
ViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WpfApplication1.Models;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication1
{
public class LinesViewModel : INotifyPropertyChanged
{
public int Cost
{
get
{
return Lines.Sum(x => x.X + x.Y);
}
}
public ObservableCollection<Line> Lines
{
get;
private set;
}
public LinesViewModel()
{
Lines = new ObservableCollection<Line>();
Lines.Add(new Line()
{
Name = "Line1",
X = 0,
Y = 1
});
Lines.Add(new Line()
{
Name = "Line2",
X = 1,
Y = 1
});
Lines.Add(new Line()
{
Name = "Line3",
X = 2,
Y = 2
});
foreach(Line line in Lines)
{
line.XChanged += new EventHandler(lineChanged);
line.YChanged += new EventHandler(lineChanged);
}
Lines.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Lines_CollectionChanged);
}
private void Lines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Line line in e.NewItems)
{
line.XChanged += new EventHandler(lineChanged);
line.YChanged += new EventHandler(lineChanged);
}
}
if (e.OldItems != null)
{
foreach (Line line in e.OldItems)
{
line.XChanged -= new EventHandler(lineChanged);
line.YChanged -= new EventHandler(lineChanged);
}
}
}
private void lineChanged(object sender, EventArgs e)
{
PropertyChanged(this, new PropertyChangedEventArgs("Cost"));
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
}
модель
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1.Models
{
public class Line
{
private int x;
private int y;
public String Name { get; set; }
public int X
{
get
{
return x;
}
set
{
x = value;
XChanged(this, EventArgs.Empty);
}
}
public int Y
{
get
{
return y;
}
set
{
y = value;
YChanged(this, EventArgs.Empty);
}
}
public event EventHandler XChanged = delegate { };
public event EventHandler YChanged = delegate { };
}
}
Чтобы вручную создать ваши LineViewModels с помощью Prism/MEF, вы можете использовать контейнер для разрешения зависимостей, для чего он и нужен.
Например,
LineViewModel line = container.GetExportedValue<LineViewModel>();
См. Эту ссылку: Управление зависимостями: разрешение экземпляров с помощью MEF.
Я немного обеспокоен вашим дизайном, действительно ли необходимо, чтобы каждая из ваших строк имела ViewModel и создавалась контейнером, а зависимости вводились? Возможно ли, что мог быть один объект, который управляет всеми строками и имеет эти введенные зависимости? Возможно, какая-то модель репозитория может принести вам пользу?
Это может привести к значительным накладным расходам, если вы разрешаете тысячи объектов через контейнер. Книга Prism также упоминает, что это не может быть хорошей идеей. Соображения по использованию контейнера