JMcCarty
JMcCarty

Reputation: 759

Correct implementation of MVVM for data displayed in two views with different display techniques

I've looked around on google and cannot figure out the proper protocol for displaying this data.

My application is displaying the same core data in two different views (a canvas and a treeview) side by side but each requires a different layout. The canvas simply uses a flat ObservableList to display user objects on screen. The treeview will provide categorized list of that data. Due to the need for a hierarchy in the one view and not the other, does it make sense to create additional viewmodels to wrap the data?

I would like to reuses the viewmodels as much as possible but want to avoid creating any "god" classes.

Example:

Canvas:
- - - - - - - - - - - - - - - 
|    Person1      Person2   |
|  Person3      Person4     |
- - - - - - -  - - - -  - - -

TreeView:
People:
 -Adults
   -Person1
   -Person4
 -Children
   -Person2
 -Teens
   -Person3

Sorry for the terrible drawing.

Upvotes: 1

Views: 326

Answers (4)

Michael Brown
Michael Brown

Reputation: 9153

Josh Smith provided a great writeup on how to use MVVM with TreeViews. Using that approach, I would recommend a TreeView specific view model. Although you could in theory combine the two, the concerns would get mixed up.

Upvotes: 0

Rachel
Rachel

Reputation: 132588

@JMcCarty You asked me to explain my comment above but it was too much to put in a comment

You would get your ObservableCollection<People> from your DataSource, and expose that via one public property for the Canvas. You'd then create a 2nd public property for the TreeView, and parse your People collection into it.

Something like this:

public class PeopleTreeItem
{
    public string Header;
    public ObservableCollection<object> Items;

    public PeopleTreeItem(string header, IEnumerable<object> items)
    {
        Header = header;
        Items = new ObservableCollection<object>() { items };
    }
}

public class SomeViewModel : ViewModelBase
{
    private ObservableCollection<Person> _peopleList;
    private PeopleTreeItem _peopleTree;

    public ObservableCollection<Person> PeopleList
    {
        get { return _people; }
    }

    public PeopleTreeItem PeopleTree
    {
        get 
        { 
            if (_peopleTree == null)
            {
                _peopleTree = new PeopleTreeItem();

                _peopleTree.Add(new PeopleTreeItem("Adults", PeopleList.Where(p => p.Type == "Adult")));
                _peopleTree.Add(new PeopleTreeItem("Teens", PeopleList.Where(p => p.Type == "Teen")));
                _peopleTree.Add(new PeopleTreeItem("Children", PeopleList.Where(p => p.Type == "Child")));
            }
            return _people; 
        }
    }

Upvotes: 2

Ben
Ben

Reputation: 1216

I think, you just need to create another object based on List of Persons like:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using GalaSoft.MvvmLight;

namespace XXXX.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        private ObservableCollection<Person> _people;
        public ObservableCollection<Person> People
        {
            get { return _people; }
            set
            {
                if (value == _people) return;
                _people = value;
                RaisePropertyChanged("People");
                RaisePropertyChanged("HierarchyPeople");
            }
        }

        public HierarchyPeople HierarchyPeople
        {
            get
            {
                //=====> Change _people to new format
                return new HierarchyPeople(_people);
            }
        }
    }

    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Gategory Gategory { get; set; }
    }

    public class Gategory
    {
    }

    public class HierarchyPeople : Dictionary<Gategory, List<Person>>
    {
        public HierarchyPeople(ObservableCollection<Person> people)
        {
            var categories = people.Select(p => p.Gategory).Distinct();

            foreach (var cat in categories)
                this.Add(cat, people.Where(p => p.Gategory == cat).ToList());
        }
    }
}

Upvotes: 2

Bathineni
Bathineni

Reputation: 3496

i think you can achieve this using a simple linq query...

here is a sample.. I did this in code behind file you can do something similar in you viewmodel

public partial class Window1 : UserControl
    {
        List<Person> CanvasDatasource { get; set; }
        List<Category> TreeViewDatasource { get; set; }

        public Window1()
        {
            InitializeComponent();
            TreeViewDatasource = new List<Category>();

            for (int i = 0; i < 5; i++)
            {
                Category c = new Category();
                c.Name = "category" + i;
                for (int j = 0; j < 5; j++)
                {
                    c.persons.Add(new Person { Name = "Person " + j });
                }

                TreeViewDatasource.Add(c);
            }

            CanvasDatasource = TreeViewDatasource.SelectMany(i => i.persons.Select(j => j)).ToList();

        }


    }

    class Category
    {
        public Category()
        {
            persons = new List<Person>();
        }
        public string Name { get; set; }
        public List<Person> persons { get; set; }
    }

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

In the "TreeViewDatasource" you will get categorized persons and in "CanvasDatasource" you will get flat list of persons

Upvotes: 2

Related Questions