Eric after dark
Eric after dark

Reputation: 1808

How to add TreeViewItems to a TreeView Control

This question is a follow up to this question. I've taken some advice from this site and decided to start learning MVVM implementation for my work with TreeViews. With that being said I am VERY new to MVVM and I'm still getting familiar with the syntax and implementation.

I have a TreeView that displays integer-type data but I would like it to work with strings instead. The tree also allows the user to add to any level by selecting the TreeViewItem and then typing in the new integer header into the textBox, and then clicking a button.

Example Image

I'd like for a parent, child, and grandchild to be available at start-up with pre-defined names. Another thing to note is that that user will only be able to add to the TreeView at the level of the child (so they'll only be able to add grandchildren).

Model

public class TreeViewModel : PropertyChangedBase
{
    public string Value { get; set; }

    public ObservableCollection<TreeViewModel> Items { get; set; }

    public CollectionView ItemsView { get; set; }

    public TreeViewModel(string value)
    {
        Items = new ObservableCollection<TreeViewModel>();
        ItemsView = new ListCollectionView(Items)
        {
            SortDescriptions =
            {
                new SortDescription("Value",ListSortDirection.Ascending)
            }
        };
        Value = value;
    }
}

ViewModel

public class SortedTreeViewWindowViewModel : PropertyChangedBase
{
    private string _newValueString;

    public string NewValueString
    {
        get { return _newValueString; }
        set
        {
            _newValueString = value;

            OnPropertyChanged("NewValueString");
        }
    }

    public TreeViewModel SelectedItem { get; set; }

    public ObservableCollection<TreeViewModel> Items { get; set; }

    public ICollectionView ItemsView { get; set; }

    public SortedTreeViewWindowViewModel()
    {
        Items = new ObservableCollection<TreeViewModel>();
        ItemsView = new ListCollectionView(Items) { SortDescriptions = { new SortDescription("Value", ListSortDirection.Ascending) } };
    }

    public void AddNewItem()
    {
        ObservableCollection<TreeViewModel> targetcollection;

        //Insert the New Node as a Root node if nothing is selected.
        targetcollection = SelectedItem == null ? Items : SelectedItem.Items;

        if (_newValueString != null)
        {
            targetcollection.Add(new TreeViewModel(_newValueString));
            NewValueString = string.Empty;
        }
    }
}

View Code-Behind

public partial class Window1 : Window
{
    public SortedTreeViewWindowViewModel ViewModel { get { return DataContext as SortedTreeViewWindowViewModel; } set { DataContext = value; } }

    public Window1()
    {
        InitializeComponent();
        ViewModel = new SortedTreeViewWindowViewModel()
            {
                Items = {new TreeViewModel("Test")}
            };
    }

    private void AddNewItem(object sender, RoutedEventArgs e)
    {
        ViewModel.AddNewItem();
    }

    private void OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        ViewModel.SelectedItem = e.NewValue as TreeViewModel;
    }
}

Thanks so much for the help. I'm hoping that going through this will help me understand how to edit and build ViewModels so that I can learn to improvise a little more in the future.

UPDATE

The TreeView is now composed of strings, so that part is solved. I still need help with the default nodes though. I have updated my code to reflect this change.

Upvotes: 1

Views: 4062

Answers (1)

Tyler Morrow
Tyler Morrow

Reputation: 961

Here are my suggestions

  • Change the places where you have int to string. The TreeView should handle that change.
  • In the constructor of your ViewModel, manually insert your default nodes. Make sure you understand how to work with a TreeView as that will affect the design of your Model and ViewModel and naturally improve the implementation.

Here is a very simple example how to fill a tree in the ViewModel which is bound to a TreeView in the View:

View

<Window x:Class="TreeViewExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <StackPanel>
            <TreeView ItemsSource="{Binding Tree}"/>
        </StackPanel>
    </StackPanel>
</Window>

View Code-Behind

namespace TreeViewExample
{
    using System.Windows;

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            DataContext = new MainWindowViewModel();
            InitializeComponent();
        }
    }
}

ViewModel

namespace TreeViewExample
{
    using System.Collections.ObjectModel;
    using System.Windows.Controls;

    class MainWindowViewModel
    {
        public ObservableCollection<TreeViewItem> Tree { get; set; }

        public MainWindowViewModel()
        {
            Tree = new ObservableCollection<TreeViewItem>();
            Tree.Add(GetLoadedTreeRoot());
        }

        private TreeViewItem GetLoadedTreeRoot()
        {
            TreeViewItem parent = new TreeViewItem() { Header = "Parent" };
            TreeViewItem child1 = new TreeViewItem() { Header = "Child 1" };
            TreeViewItem child2 = new TreeViewItem() { Header = "Child 2" };
            TreeViewItem grandchild1 = new TreeViewItem() { Header = "Grandchild 1" };
            TreeViewItem grandchild2 = new TreeViewItem() { Header = "Grandchild 2" };

            child1.Items.Add(grandchild1);
            child2.Items.Add(grandchild2);
            parent.Items.Add(child1);
            parent.Items.Add(child2);
            return parent;
        }
    }
}

Produces:

  • Parent
    • Child 1
      • Grandchild 1
    • Child 2
      • Grandchild 2

Additional thoughts:

  • To clean up your code-behind, you might look up a Command implementation, of which there are many. Although you sometimes need it, avoid code in the code-behind when possible. I really like this example because it shows you a general MVVM implementation without getting into advanced Command-related topics (ItemTemplates, Interactivity namespace, etc.).

Upvotes: 3

Related Questions