2011-01-05 57 views
2

我试图在绑定到CollectionViewSource的WPF中创建一个TreeView。我在CollectionViewSource中创建组,并在XAML中设置HierarchicalDataTemplate以正确显示TreeView。WPF TreeView动态分组

在我的ViewModel中,我有一个方法来改变CollectionViewSource的分组,并且一切似乎都很好。我唯一的问题是显示没有任何分组的CollectionViewSource。

有谁知道如何设计模板以适应CollectionViewSource没有分组的场景,但是也可以容纳带分组的CollectionViewSource?

更新 我已经创建了一些示例代码来更好地描述我在做什么。 DataTemplateSelector在应用程序启动时工作,但当用户从组合框中选择不同的分组选项时,我无法弄清楚如何重新启动DataTemplate选择器。下面是我的示例代码

<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> 

背后

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; 
     } 
    } 
} 
} 

回答

-1

也许this代码将有助于不清楚。

+0

没有太多的帮助,但我要编辑原始问题以包含示例代码。 – Amit 2011-01-06 22:41:57

0

您可以通过创建一个绑定到区间变量的Converter来重写ItemTemplateSelector。

+0

感谢乔尔 - 我是转换器的新手,所以我想知道我应用了什么转换器? – Amit 2011-01-07 01:54:40

+0

我只是看了一遍你的代码,我想我已经部​​分错了。你绑定到Selector,但你只在InitializeComponent中设置一次,因此绑定到你的选择器只发生一次。您需要将ItemTemplateSelector绑定到组合框的SelectedItem,以便在选择不同的东西时更改它。这是转换器可以提供帮助的地方。转换器将允许您将组合框中的对象转换为DataTemplateSelector。 – 2011-01-07 04:35:44