【问题标题】:WPF TreeView Dynamic GroupingWPF TreeView 动态分组
【发布时间】:2011-01-05 23:04:26
【问题描述】:

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

在我的 ViewModel 中,我有一种方法可以更改 CollectionViewSource 的分组,并且一切似乎都运行良好。我唯一遇到的问题是在没有任何分组的情况下显示 CollectionViewSource。

有谁知道如何设计模板以适应 CollectionViewSource 没有分组但也能适应 CollectionViewSource 有分组的情况?

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

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

【问题讨论】:

    标签: wpf mvvm treeview mvvm-light collectionviewsource


    【解决方案1】:

    您可以通过创建一个绑定到区间变量的转换器来重新触发 ItemTemplateSelector。

    【讨论】:

    • 谢谢乔尔 - 我是转换器的新手,所以我想知道我将转换器应用于什么?
    • 我刚刚又看了一遍你的代码,我想我有部分错误。您正在绑定到选择器,但您只在 InitializeComponent 中设置了一次,因此与选择器的绑定只发生一次。您需要将 ItemTemplateSelector 绑定到组合框的 SelectedItem ,以便在您选择不同的内容时它会发生变化。这就是转换器可以提供帮助的地方。该转换器将允许您将组合框中的对象转换为 DataTemplateSelector。
    【解决方案2】:

    也许this 会帮助不确定。

    【讨论】:

    • 帮助不大,但我将编辑原始问题以包含示例代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多