2

I'm attempting to create a TreeView in WPF that is bound to a CollectionViewSource. I create groups in the CollectionViewSource and have the HierarchicalDataTemplate setup in the XAML to display the TreeView properly.

In my ViewModel I have a method to change the Grouping of the CollectionViewSource and all seems to work well. The only issue I have is displaying the CollectionViewSource without any grouping.

Does anyone know how to design the template to accommodate a scenario where the CollectionViewSource has no groupings, but can also accommodate a CollectionViewSource with groupings?

Update I have created some sample code to better describe what I'm doing. The DataTemplateSelector works when the app starts but I can't figure out how to re-fire the DataTemplate Selector when the user selects a different grouping option from the combobox. Below is my sample code

<Window
x:Class="TreeViewGroupTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TreeViewGroupTest"
Title="WindowsApplication1"
Height="Auto" Width="300">

<Window.Resources>

    <local:SchoolTemplateSelector x:Key="schoolTemplateSelector" />

    <HierarchicalDataTemplate x:Key="BasicList" ItemsSource="{Binding TeachersBy.Source}">
        <StackPanel>
            <TextBlock Text="{Binding Name}" />
            <ComboBox SelectionChanged="ComboBox_SelectionChanged" ItemsSource="{Binding GroupByList}" />
        </StackPanel>
        <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Last}" />
            </DataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="GroupList" ItemsSource="{Binding TeachersBy.View.Groups}">
        <StackPanel>
            <TextBlock Text="{Binding Name}" />
            <ComboBox SelectionChanged="ComboBox_SelectionChanged" ItemsSource="{Binding GroupByList}" />  
        </StackPanel>
        <HierarchicalDataTemplate.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                <TextBlock Text="{Binding Name}" />
                <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Last}" />
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>
            </HierarchicalDataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
    </HierarchicalDataTemplate>
</Window.Resources>

<StackPanel>        
    <TreeView  ItemsSource="{Binding Schools}" ItemTemplateSelector="{Binding schoolTemplateSelector}" />
</StackPanel>

and the code behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;    
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;    
using System.Windows.Media;    
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace TreeViewGroupTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public ObservableCollection<School> Schools { get; set; }
    public SchoolTemplateSelector schoolTemplateSelector { get; set; }

    private string group = "Subject";
    public string GroupByChoice { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        GroupByChoice = "Subject";

        Schools = new ObservableCollection<School> {
            new School
            {
                Name = "Apple",
                Teachers = new ObservableCollection<Teacher> {
                    new Teacher { Last = "Alpha", Subject = "Math" , Grade = "9th" },
                    new Teacher { Last = "Beta", Subject = "English" , Grade = "9th" },
                    new Teacher { Last = "Charlie", Subject = "Math" , Grade = "9th" },
                    new Teacher { Last = "Delta", Subject = "English" , Grade = "10th" },
                    new Teacher { Last = "Echo", Subject = "Math" , Grade = "10th" },
                    new Teacher { Last = "Foxtrot", Subject = "English" , Grade = "10th" },
                }
            },
            new School
            {
                Name = "Microsoft",
                Teachers = new ObservableCollection<Teacher> {
                    new Teacher { Last = "Alpha", Subject = "Math" , Grade = "9th" },
                    new Teacher { Last = "Beta", Subject = "English" , Grade = "9th" },
                    new Teacher { Last = "Charlie", Subject = "Math" , Grade = "9th" },
                    new Teacher { Last = "Delta", Subject = "English" , Grade = "10th" },
                    new Teacher { Last = "Echo", Subject = "Math" , Grade = "10th" },
                    new Teacher { Last = "Foxtrot", Subject = "English" , Grade = "10th" },
                }
            },
        };

        Schools[0].SetTeacher(); ;
        Schools[1].GroupBy("Subject");
        Schools[1].TeachersBy.View.Refresh();

        this.DataContext = this;

        schoolTemplateSelector = new SchoolTemplateSelector();

    } 

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        string prop = e.AddedItems[0].ToString();

        if (prop != "None")
        {
            foreach (School s in Schools)
            {
                s.GroupBy(prop);
            }
        }
        else
        {
            foreach (School s in Schools)
            {
                s.TeachersBy.GroupDescriptions.Clear();
            }
        }      

        //The DataTemplateSelector should fire now...
    }
}

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

    public ObservableCollection<Teacher> Teachers { get; set; }

    public CollectionViewSource TeachersBy { get; set; }

    public ObservableCollection<String> GroupByList { get; set; }

    public School()
    {
        Teachers = new ObservableCollection<Teacher>();
        TeachersBy = new CollectionViewSource();

        GroupByList = new ObservableCollection<string> {
            "None", "Subject", "Grade"
        };
    }

    public void SetTeacher()
    {
        TeachersBy.Source = Teachers;
    }

    public void GroupBy(string propertyName)
    {
        TeachersBy.Source = Teachers;
        TeachersBy.GroupDescriptions.Clear();
        TeachersBy.GroupDescriptions.Add(new PropertyGroupDescription(propertyName));
        TeachersBy.View.Refresh();
    }

}

public class Teacher
{
    public string Last { get; set; }
    public string Subject { get; set; }
    public string Grade { get; set; }
    public Teacher() { }
}

public class SchoolTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if (item is School && (item as School).TeachersBy.GroupDescriptions.Count > 0)
        {
            return
                element.FindResource("GroupList")
                       as DataTemplate;
        }
        else
        {
            return
                element.FindResource("BasicList")
                       as DataTemplate;
        }
    }
}
}
Amit
  • 103
  • 1
  • 8

2 Answers2

0

You can refire the ItemTemplateSelector by creating a Converter thats bound to an interval variable.

Joel Lucsy
  • 8,520
  • 1
  • 29
  • 35
  • Thanks Joel - I'm new to Converters, so I'm wondering what am I applying the Converter to? – Amit Jan 07 '11 at 01:54
  • I just looked at your code again, I think I got it partially wrong. You're binding to the Selector, but you only set that one up once in InitializeComponent, therefore the binding to your selector only happens once. You need to bind the ItemTemplateSelector to the SelectedItem of the combobox so that it changes when you pick something different. This is where the converter would help. The converter would allow you to convert from the objects in the combobox to a DataTemplateSelector. – Joel Lucsy Jan 07 '11 at 04:35
-1

Maybe this will help not sure.

Chen Kinnrot
  • 20,609
  • 17
  • 79
  • 141
  • Wasn't too much help, but I am going to edit the original question to include sample code. – Amit Jan 06 '11 at 22:41