This question relates to design help. In it I present a problem, and some solutions I thought of, together with my opinions of the solutions; and finally a solution I think is the correct one. I am seeking validation or challenges to my solutions. Sorry for the long post.
I have a ConfigActivityGroup
class (model). It represents a group of activities. A user can have many ActivityGroups
, each containing a name for the group and multiple activities which are strings.
I have a ConfigActivityGroupVM
which provides Commands for CRUD on ConfigActivityGroups
The ConfigActivityGroupVM
keeps an ObservableList<ConfigActivityGroup> for the ConfigActivityGroups
. The ConfigActivityGroupVM
also keeps a CollectionViewSource
for the ObservableList<ConfigActivityGroup> and presents an ICollectionView
for the UI to access.
I haven't done the UI yet, but I planned on having the ICollectionViewSource
bound to a list, from which the user can click an item; and see a text box with the GroupName, and another list with the Activities
for the ActivityGroup
adjacent to the first list.
This is all good, as I have a concept of a current ConfigActivityGroup
provided by the ICollectionView
. I can use the current ConfigActivityGroup
to bind to the second UI list to show the Activities
in the current ConfigActivityGroup
.
Problem: When I want to build Commands for CRUD
on the activities of the current ConfigActivityGroup
.
If the Activities
in the ConfigActivityGroup
are in a List<string>
and I bind them directly to the UI then I have no concept of a "current" activity to which I can bind-to in the UI so that I could have a DeleteCurrentActivityCommand
command in the VM delete the current activity for the current command.
First Solution I had was to, upon selection of a ConfigActivityGroup
in the VM (through the ICollectionView), to copy the activities from the selected ConfigActivityGroup
into a new ObservableCollection<string>
in the VM (which in turn has it's own ViewSource
and ICollectionView
). Then, I could have the UI second list to bind to ICollectionView of the activities of the current ConfigActivityGroup
. As such, my commands would modify the activities' ICollectionView. However, I ran into a roadblock when I tried to make a new activity for the current ConfigActivityGroup
in which I couldn't set the activities' ICollectionView.CurrentItem
to be a different activity string (since it's read only).
I thought one solution to that was to box up the activity string in an ActivityString
class has a single string. Overall, I wasn't too happy with this method.
Second Solution I thought, was to make the List<string>
in the ConfigActivityGroup
to be an ObservableCollection<string>
. That would simplify the VM. I hesitate to use this approach since the model is loaded from the database from a non-UI thread through magic json-deserialisation
(MyCouch + CouchDB) and then problems arise (I think, from memory) when the ObservableCollection
is accessed from a thread different from its creation thread. I thought that using one of the many thread-safe ObservableCollections was overkill.
Third Solution I thought while writing this question was to keep the model List<string>
for the activities in the ConfigActivityGroup
. Then, upon a ConfigActivityGroup
being selected in its ICollectionView
, initialising a CollectionViewSource/ICollection
with the List<string>
of activities directly as the source. That way the UI can bind to the activities directly and the UI can take care of editing the actual activity string; and the concept of a currently selected activity remains, which I can then delete using a command.
I think the third approach is the correct approach, but I am open to hearing what the community thinks. This is my first use of MVVM, and i'm trying to keep responsibilities separated and trying to use Commands as much as possible.
Extra data:
- Once the ConfigActivityGroup is loaded from the database and put into the VM, it will not be changed by anyone else than the VM itself through the UI.