How to sync data in MVVM when using collections - c#

Recently I have started to dig into MVVM to structure a WPF application I am working on. I am struggling to understand how I can keep collections in sync between Model and ViewModel, and in conjunction with that, how to validate information the user will enter.
Suppose I have a (theoretical) class Building, the model, that will store a building layout, during runtime in memory, and otherwise in xml via serialization. Building has a member List, and each entry Floor in that list can have other Lists, like List and List, which could again have members which are Lists (ie. List).
The model:
namespace TestMVVM
{
public class Building
{
public string strName { get; set; }
public List<Floor> floors { get; set; }
}
public class Floor
{
public int iNumber { get; set; }
public List<Room> rooms { get; set; }
}
public class Room
{
public int iSize { get; set; }
public string strName { get; set; }
public List<Door> doors { get; set; }
}
public class Door
{
public bool bIsLocked { get; set; }
}
}
In the View, the List of type Floor will be editable in a DataGrid. The user can enter a new row in the DataGrid to add a Floor to the Building class. In another DataGrid, Rooms could be added to a Floor. This is quite easy when I make all Lists into ObservableCollections, and directly couple them with the View. However, this also means there is no proper separation of concerns, and it gets messy once validation comes into play.
So I wrote a ViewModel class, BuildingViewModel. It will hold a reference to an instance of the model. This is where I run into trouble: the ViewModel will hold an ObservableCollection of type FloorViewModel. But when the user adds an entry, how do I also add an entry to the List in the model? And mostly, keep the data in sync? What if a Room is added to a Floor, or a Door to a Room, how to know where in the Model to update which data? Ie. how to sync nested List member data?
Subsequently I would to make sure no duplicate Floors can be created; ie. if the user adds a floor with a number that is already in the List, the DataGrid must report an error. Same if an existing floor is edited, and same for Room names. I would think that kind of error checking cannot happen within the FloorViewModel class, because it has no access to other instances of itself.
I have searched a lot but found no clear answer to this. It would seem like a rather common situation? Maybe I am simply going in the wrong direction with this?
This is the current ViewModel, where ViewModelBase is a generic class holding implementations of INotifyProretyChanged and INotifyDataErrorInfo.
namespace TestMVVM
{
public class BuildingViewModel : ViewModelBase
{
private Building building;
public string strName
{
get { return building.strName; }
set
{
building.strName = value;
if (value == "") AddError("strName", "Name cannot be empty.");
OnPropertyChanged("strName");
}
}
public ObservableCollection<FloorViewModel> floors
{
// what goes here? how to sync members of floor to the model, and validate data?
}
public BuildingViewModel(Building b)
{
building = b;
}
}
public class FloorViewModel : ViewModelBase
{
public ObservableCollection<Room> rooms
{
// what goes here? how to sync members of room to the right Floor of the model, and validate data?
}
}
// etc
}

There is a problem in the classes, that You provided. Try to apply the law of Demeter, watch this video about how to structure correctly the House object (even same example), than You only call the correct level's addX() method, that will validate.

Look you need to read again MVVM concept.. All the idea is to have one view model per each view. In our situation try this:
namespace TestMVVM
{
public class BuildingViewModel : ViewModelBase
{
private Building building;
private ObservableCollection<Floor> _floors;
public string strName
{
get { return building.strName; }
set
{
//building.strName = value;
if (String.IsNullOrEmpty(value))
{
AddError("strName", "Name cannot be empty.");
return;
}
building.strName = value;
OnPropertyChanged("strName");
}
}
public ObservableCollection<Floor> floors
{
get
{
return _floors;
}
set
{
_floors = value;
}
}
public BuildingViewModel(Building b)
{
building = b;
}
public void AddNewFloor(Floor)
{
// valid your floor
// floors.Add(floor);
}
}
Now I suggest you to add function that will validate your changes in floors and not in the setter of the property.

Or override/create ObservableCollection class and redefine all methods :
public class MyObservableCollection<T> : ICollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public event PropertyChangedEventHandler PropertyChanged;
public int Count { get { return _reference.Count; } }
public bool IsReadOnly { get { return _reference.IsReadOnly; } }
private readonly IList<T> _reference;
public MyObservableCollection(IList<T> reference)
{
_reference = reference;
}
public IEnumerator<T> GetEnumerator()
{
return _reference.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T item)
{
_reference.Add(item);
SendNotification();
}
public void Clear()
{
_reference.Clear();
SendNotification();
}
public bool Contains(T item)
{
return _reference.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_reference.CopyTo(array, arrayIndex);
}
public bool Remove(T item)
{
var result = _reference.Remove(item);
SendNotification();
return result;
}
private void SendNotification()
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(new NotifyCollectionChangedAction()));
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("..."));
}
}
}

Why you don't change type (List to ObservableCollection) on Model ?
In this case :
public ObservableCollection<FloorViewModel> floors
{
get{return building.floors;}
}

Related

How do I change the values of variables within one class, from another?

Please excuse my ignorance for I am new to C#.
I am currently working on an MVVM project in which a viewmodel has multiple instantiated public variables that are data-bound to elements in a view (WPF). When these variables are changed they automatically update in my view. Take for instance the code segment below from my view model...
private string _displaybind;
public string DisplayBind
{
get { return _displaybind; }
set
{
SetProperty(ref _displaybind, value);
if (_displaybind.Length > 5000)
{
DisplayBind = _displaybind.Substring(_displaybind.IndexOf('\n') + 1);
}
}
}
By using the command DisplayBind = "Hello"; within my viewmodel I can push out text to a textbox I have located in my XAML view. Unfortunately, I have reached a point where I can not simply edit the value of DisplayBind.
I need to start a state machine within my viewmodel which will access several states (classes) in separate C# files. However, I have no idea how to receive, and more importantly edit the values within my viewmodel from these separate classes.
I start my state machine in my viewmodel using this...
IPMProgram ipmprogram = new IPMProgram();
ipmprogram.StartTheIPMProgram();
This is my IPMProgram class
public class IPMProgram
{
public IPMProgramState currentState = null;
public IPMProgram()
{
currentState = new BootBannerState(this);
}
public void StartTheIPMProgram()
{
while (true)
{
currentState.GetNextState();
}
}
}
This is my IPMProgramState class
public abstract class IPMProgramState
{
private IPMProgram ipmprogram;
public IPMProgram Ipmprogram
{
get { return ipmprogram; }
set { ipmprogram = value; }
}
public abstract void GetNextState();
}
And this is my BootBannerState class (The state I want to edit DisplayBind from)
class BootBannerState : IPMProgramState
{
public BootBannerState(IPMProgramState state)
:this(state.Ipmprogram)
{
}
public BootBannerState(IPMProgram ipmprograminstance)
{
this.Ipmprogram = ipmprograminstance;
}
public override void GetNextState()
{
//DisplayBind = "Hello"!
return;
}
}
Someone suggested that I should look into Dependency Injection, but I don't quite understand how it would work for me. What should I do?
Thank you for all of your help,
Tesnich

How do I detect changes in nested properties?

In C#, I have a suffiently complex Model. I already have a WPF Client to manipulate that model. I'm using MVVM. All objects in that model support INotifyPropertyChanged and all properties that are collections support INotifyCollectionChanged.
Take this as a simplied example:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace CollectionTest1
{
public class PropertyChangedSupport : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Company : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<Employee> Employees { get; } = new ObservableCollection<Employee>();
}
public class Employee : PropertyChangedSupport
{
private string name;
public String Name { get { return name; } set { name = value; FirePropertyChange(); } }
public ObservableCollection<PresentTimespan> PresentTimespans { get; } = new ObservableCollection<PresentTimespan>();
public Boolean IsPresentAt(DateTime t)
{
foreach (PresentTimespan pt in PresentTimespans)
{
if (pt.Start.CompareTo(t) <= 0 && pt.Finish.CompareTo(t) >= 0) return true;
}
return false;
}
}
public class PresentTimespan : PropertyChangedSupport
{
private string comment;
public String Comment { get { return comment; } set { comment = value; FirePropertyChange(); } }
private DateTime start;
public DateTime Start { get { return start; } set { start = value; FirePropertyChange(); } }
private DateTime finish;
public DateTime Finish { get { return finish; } set { finish = value; FirePropertyChange(); } }
}
public class CompanyStatusView : PropertyChangedSupport
{
private DateTime currentTime;
public DateTime CurrentTime { get { return currentTime; } set { currentTime = value; FirePropertyChange(); } }
private Company currentCompany;
public Company CurrentCompany { get { return currentCompany; } set { currentCompany = value; FirePropertyChange(); } }
public ObservableCollection<Employee> PresentEmployees { get; } = new ObservableCollection<Employee>();
public CompanyStatusView()
{
UpdatePresentEmployees();
}
private void UpdatePresentEmployees()
{
PresentEmployees.Clear();
foreach (Employee e in CurrentCompany.Employees) {
if (e.IsPresentAt(currentTime)) PresentEmployees.Add(e);
}
}
}
}
I'd like to have UpdatePresentEmployees called whenever there are changes in:
Collection Company.Employees.PresentTimespans
Property Company.Employees.PresentTimespans.Start
Property Company.Employees.PresentTimespans.Finish
Collection Company.Employees
Property CurrentTime
Property CurrentCompany
So it's basically any property or collection read by UpdatePresentEmployees.
My best solution so far included registering a lot of event handlers to all the objects mentioned above. That included to have a couple of Dictionary instances to track which added objects I have to subscribe to and especially which I have to unsubscribe from.
The most difficult and annoying part was to subscribe to all the PresentTimespan objects to listen for property changes and all the PresentTimespans collections of Employee to listen for collection changes.
My guess is that there has to be a better way to do this.
After all, in JFace (Java) there is a very interesting solution that uses ObservableTracker. So there you'd only provide the code for UpdatePresentEmployees and ObservableTracker tracks which objects have been read and automatically makes you listen for changes in any of these and also correctly unsubscribes from irrelevant objects. So there are better approaches to this problem in general. What is C# offering? Can it do better than my best solution I mentioned above? Can I avoid some of the boilerplate code? Can it be done with .net provided classes or do I need some additional classes/libraries?
Thanks for your kind help and advice in advance!
You could use BindingList instead of ObservableCollection and attach to the the ListChanged Event. But keep in mind that BindingList has some disadvantages like not being very fast. For further information this could be interesting: difference between ObservableCollection and BindingList
If you dont wanna use BindingList you have to wire your items with events.
As pointed out by Nikhil Agrawal, Rx or ReactiveUI is a good framework for my purpose. So I consider that to be a solution.

Collection of comboBoxes in WinForms

I am working on small winforms app. One of my forms contains few comboBoxes:
As I am trying to use MVP pattern in my project, so I decided to create View and Presenter for that form. The communicate via adequate interface.
ComboBox can be fully decribed (for my needs) with its DataSource (i.e. list os strings) and SelectedIndex. That' s why I created proper interface:
public interface IMyView
{
MyViewPresenter { set; }
IEnumerable<string> ComboBox1stDataSource { get; set; }
int ComboBox1SelectedIndex { get; set; }
IEnumerable<string> ComboBox2ndDataSource { get; set; }
int ComboBox2ndSelectedIndex { get; set; }
//for third comboBox it will be the same
}
I implemented that interface in my View class:
public partial class MaterialDatabasePropertiesForm : Form, IMaterialDatabasePropertiesView, IMyView
{
public MaterialDatabasePropertiesPresenter Presenter { private get; set; }
public IEnumerable<string> ComboBox1stDataSource
{
get { return comboBox1st.DataSource as List<string>; }
set { comboBox1st.DataSource = value; }
}
public int ComboBox1SelectedIndex
{
get { return comboBox1st.SelectedIndex; }
set { comboBox1st.SelectedIndex = value; }
}
public IEnumerable<string> ComboBox2ndDataSource
{
get { return comboBox2nd.DataSource as List<string>; }
set { comboBox2nd.DataSource = value; }
}
public int ComboBox2ndSelectedIndex
{
get { return comboBox2nd.SelectedIndex; }
set { comboBox2nd.SelectedIndex = value; }
}
}
When everything is set like above I use properties declared in Interface in my Presenter to change properties of comboBoxes in form.
Although it may seem like a good solution it isn' t enough for me. In my origial application I have 14 comboBoxes, and that number may change in future.
What I am trying to is making it more elastic. I was thinking about creatin some collection of comboBoxes in view, but I can' t figure it out.
My sample solutin is bad, as it doesn' t even compile:
private List<List<string>> collectionOfComboBoxesDataSources = new List<List<string>>()
{
ref comboBox1st.DataSource, // I get error:
ref comboBox2nd.DataSource, // "Cannot acces non-static field
ref comboBox3rd.DataSource // <comboBoxName> in static context"
};
//this property would be part of IMyView
public List<List<string>> CollectionOfComboBoxesDataSources
{
get { return collectionOfComboBoxesDataSources; }
set { collectionOfComboBoxesDataSources = value; }
}
What can I do to create collection (or something working similar) to acces my comboBoxes properties?
You could try to iterate through your form.
List<ComboBox> listOfCombobox = new List<ComboBox>();
foreach(var combobox in this.controls.OfType<ComboBox>())
{
listOfCombobox.Add(combobox);
}
If you're trying to do this.
Then you can access the list via index, so you can access your properties of each combobox.

Enforcing a business rule involving multiple items

Let's say that I got a simple todolist:
interface ITodoList
{
ITodoItem Create(title);
IEnumerable<ITodoItem> Items {get;}
}
interface ITodoITem
{
void StartTrackTime();
void StopTrackTime();
}
Now I want to enforce so that time is only tracked for one item at a time (per user).
Should I create a domain event like ItemTimeTrackingStarted that StartTrackTime generates. The event would be picked up by a ITodoService which checks if there are any other time tracked items for the current user (and stop them). Or are there a better way?
well if you have dependencies between the items, which in the case is the check, my proposal would be to move the track method into the todo list object, and away from item.
So you request a change from the object that holds all todo items, and there you locate the checks as well.
IMO I'd do it like this, I don't know all the details of the context, but for this specific functionality here it goes
public interface ITrackTime
{
void StartTrackTime();
void StopTrackTime();
}
public interface ITodoItem
{
int Id {get;}
//other stuff
}
public TodoItem:ITodoITem, ITrackTime {}
public class TodoList:ITodoList,ITrackItem
{
ITodoItem Create(title)
{
//create item and add it to collection
}
TodoItem _currentlyTracking;
void StartTrackTime(int itemId)
{
if (_currentlyTracking == null)
{
// getItem and call method for item ..
item.StartTrackTime();
_currentlyTracking=item;
}
else{
//get item and check to see if it is the same id
//throw exception if it is not, ignore it if it is
}
}
}
var list = new TodoList();
ITodoItem item= list.Create("titel");
list.StartTrackingTime(item.Id);
list.StartTrackingTime(otherId); //should throw or whatever handling
Everything is contained within the AR (TodoList). One again, this is a rough draft as I'm not fully aware about the context and the domain.
As stated, the ToDoList should enforce the constraint since the constraint is defined at the ToDoList level. (Unless it is defined at the user level as you indicated in which case the responsibility would shift there). You can leave the method on the item, but it can reference the parent todo list. The code could look like this:
public class ToDoList
{
public IList<ToDoListItem> Items { get; private set; }
// factory method creates items as required by ToDoList
public ToDoListItem Create(string title)
{
var item = new ToDoListItem(this, title);
this.Items.Add(item);
return item;
}
ToDoListItem currentItem;
public void StartTrackTimeFor(ToDoListItem item)
{
if (this.currentItem != null)
throw new Exception();
// could also throw different exception if specified item is current item being tracked
// start time tracking logic.
this.currentItem = item;
}
public void StopTrackTimeFor(ToDoListItem item)
{
if (this.currentItem != item)
throw new Exception();
// stop time tracking logic.
this.currentItem = null;
}
}
public class ToDoListItem
{
public ToDoListItem(ToDoList list, string title)
{
this.ToDoList = list;
this.Title = title;
}
public ToDoList ToDoList { get; private set; }
public string Title { get; private set; }
public void StartTrackTime()
{
this.ToDoList.StartTrackTimeFor(this);
}
public void StopTrackTime()
{
this.ToDoList.StopTrackTimeFor(this);
}
}

Refactoring a list of objects to implement a business rule

I need to refactor the following class:
public interface IEmployee
{
int VacationWeeks { get; }
int YearsWithCompany { set; get; }
double Salary { set; get; }
}
public class Employee : IEmployee
{
private readonly int vacationWeeks;
public Employee(int vacationWeeks)
{
this.vacationWeeks = vacationWeeks;
}
public int VacationWeeks
{
get { return vacationWeeks; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
I need to make sure that VacationWeeks depends only on YearsWithCompany, and I am loading the mapping from the database. So far I have come up with this:
public class EmployeeNew : IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
public EmployeeNew(Dictionary<int, int> vacationWeeksTable)
{
this.vacationWeeksTable = vacationWeeksTable;
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
This class implements what I want, but it still has one vulnerability: different instances of EmployeeNew in the same collection may have been created with different instances of vacationWeeksTable.
All instances of EmployeeNew in the same collection must refer to the same vacationWeeksTable.
The application I am refactoring uses lots of List all over the system, and we need to be able to modify YearsWithCompany and Salary, yet to guarantee that only one vacationWeeksTable is used per List. These lists are iterated several times; its elements are modified in each iteration.
Here is my imperfect solution. Suggestions are welcome:
// this class does two things, which I do not like
public class EmployeeList : IEnumerable<IEmployee>, IEmployee
{
private Dictionary<int, int> vacationWeeksTable;
private List<EmployeeSpecificData> employees;
private int currentIndex;
private EmployeeSpecificData CurrentEmployee
{
get { return employees[currentIndex]; }
}
public IEnumerator<IEmployee> GetEnumerator()
{
for (currentIndex = 0; currentIndex < employees.Count; currentIndex++)
{
yield return this;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
// this is ugly repetitive code I don't like
public int YearsWithCompany
{
get { return CurrentEmployee.YearsWithCompany; }
set { CurrentEmployee.YearsWithCompany = value; }
}
// this is ugly repetitive code I don't like
public double Salary
{
get { return CurrentEmployee.Salary; }
set { CurrentEmployee.Salary = value; }
}
}
I use the following to create and init some of the classes that need default and shared behaviour. Maybe if you can refactor it will help:
It is some form of the Factory and FlyWeight patterns combined (the flyweight part can be removed in your scenario), which in addition has a concept of class Type shared handlers.
I simplified and removed some stuff that you wont need but there is more to remove, I added comments.
Usage would be: (app init)
Dictionary<int,int> vacationWeeksTable = new Dictionary<int,int>();
// fill the table
Factory<Employee>.Init(vacationWeeksTable);
The whenever you create a Employee class:
// remove grouping in the factory class to remove this null
Employee em = Factory<Employee>.Create(null);
It takes only a WeakReference to the classes so you don't have to worry about GC.
Each employee will have the shared vacationWeeksTable setup on creation, without the possibility to change it after from outside if not using the factory class.
You could change the vacation table for all running instances of Employee at any moment in the runtime of the app with:
// this will call the method registered for SetInitialdata on all instances of Employee classes.
// again remove grouping to remove that null
Factory<Employee>.Call(EventHandlerTypes.SetInitialData, null, vacTable);
Sample implementation of Employee:
class Employee : IBaseClass
{
private Dictionary<int, int> vacationWeeksTable;
public virtual void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> register)
{
group = 0; // disable different groups
register(new Key<Employee, int>(0), group, EventHandlerTypes.SetInitialData, SetVacationWeeksTable);
}
public virtual void RegisterSharedData(Action<IKey, object> regData)
{
// remove this from factory and interface, you probably dont need it
// I have been using it as a FlyWeight data store for classes.
}
private void SetVacationWeeksTable(object sender, SharedEventArgs e)
{
vacationWeeksTable = e.GetData<Dictionary<int, int>>();
}
}
Code pattern Implementation:
IBaseClass : interface that each of my classes that are creatable through a factory implement
public enum EventHandlerTypes
{
SetInitialData // you can add additional shared handlers here and Factory<C>.Call - it.
}
public class SharedEventArgs : EventArgs
{
private object data;
public SharedEventArgs(object data)
{
this.data = data;
}
public T GetData<T>()
{
return (T)data;
}
}
public interface IBaseClass
{
void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> regEvent);
void RegisterSharedData(Action<IKey, object> regData);
}
Utility generic classes:
public interface IKey
{
Type GetKeyType();
V GetValue<V>();
}
public class Key<T, V> : IKey
{
public V ID { get; set; }
public Key(V id)
{
ID = id;
}
public Type GetKeyType()
{
return typeof(T);
}
public Tp GetValue<Tp>()
{
return (Tp)(object)ID;
}
}
public class Triple<T, V, Z>
{
public T First { get; set; }
public V Second { get; set; }
public Z Third { get; set; }
public Triple(T first, V second, Z third)
{
First = first;
Second = second;
Third = third;
}
}
Factory class with slight modification to handle your scenario:
public static class Factory<C> where C : IBaseClass, new()
{
private static object initialData;
private static Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>> handlers = new Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>>();
private static Dictionary<IKey, object> data = new Dictionary<IKey, object>();
static Factory()
{
C newClass = new C();
newClass.RegisterSharedData(registerSharedData);
}
public static void Init<IT>(IT initData)
{
initialData = initData;
}
public static Dt[] GetData<Dt>()
{
var dataList = from d in data where d.Key.GetKeyType() == typeof(Dt) select d.Value;
return dataList.Cast<Dt>().ToArray();
}
private static void registerSharedData(IKey key, object value)
{
data.Add(key, value);
}
public static C Create(int? group)
{
C newClass = new C();
newClass.RegisterSharedHandlers(group, registerSharedHandlers);
// this is a bit bad here since it will call it on all instances
// it would be better if you can call this from outside after creating all the classes
Factory<C>.Call(EventHandlerTypes.SetInitialData, null, initialData);
return newClass;
}
private static void registerSharedHandlers(IKey subscriber, int? group, EventHandlerTypes type, Action<object, SharedEventArgs> handler)
{
handlers.Add(subscriber, new Triple<EventHandlerTypes, int, WeakReference>(type, group ?? -1, new WeakReference(handler)));
}
public static void Call<N>(EventHandlerTypes type, int? group, N data)
{
Call<N>(null, type, group, data);
}
public static void Call<N>(object sender, EventHandlerTypes type, int? group, N data)
{
lock (handlers)
{
var invalid = from h in handlers where h.Value.Third.Target == null select h.Key;
// delete expired references
foreach (var inv in invalid.ToList()) handlers.Remove(inv);
var events = from h in handlers where h.Value.First == type && (!#group.HasValue || h.Value.Second == (int)#group) select h.Value.Third;
foreach (var ev in events.ToList())
{
// call the handler
((Action<object, SharedEventArgs>)ev.Target)(sender, arg);
}
}
}
}
Make a class which contains a Dictionary. Creating or getting instance of this new class will load the dictionary in a consistent way. Then your BOs can take an instance of the class, thus ensuring they're all using the same data (because the class containingthe list knows how to load itself with the proper set of data).

Categories