在ComboBox中对项目进行分组

48

我有一个ListView,其中包含两种类型的对象,单个和多个。

单个对象是普通的TextBlock,而多个对象是具有项目的ComboBox。

我试图分组ComboBox中的项目,但没有成功。这可能吗?还是应该采用不同的方法?

我的目标是什么:

[ComboBox v]
    [Header  ]
    [    Item]
    [    Item]
    [Header  ]
    [    Item]

1
听起来更像是树形视图(TreeView)。 - strattonn
2
我同意...我先做了一个树形视图,但最终用户想要一个组合框... - debe
2个回答

76

这是可能的。使用一个具有GroupDescription作为ItemsSource的ListCollectionView,然后只需为您的ComboBox提供一个GroupStyle即可。请参见下面的示例:

XAML:

<Window x:Class="StackOverflow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:StackOverflow"
        xmlns:uc="clr-namespace:StackOverflow.UserControls"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <ComboBox x:Name="comboBox">
            <ComboBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Name}"/>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ComboBox.GroupStyle>
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

代码后台:

namespace StackOverflow
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();
            //this.comboBox.DataContext = this;

            List<Item> items = new List<Item>();
            items.Add(new Item() { Name = "Item1", Category = "A" });
            items.Add(new Item() { Name = "Item2", Category = "A" });
            items.Add(new Item() { Name = "Item3", Category = "A" });
            items.Add(new Item() { Name = "Item4", Category = "B" });
            items.Add(new Item() { Name = "Item5", Category = "B" });

            ListCollectionView lcv = new ListCollectionView(items);
            lcv.GroupDescriptions.Add(new PropertyGroupDescription("Category"));

            this.comboBox.ItemsSource = lcv;
        }


    }

    public class Item
    {
        public string Name { get; set; }
        public string Category { get; set; }
    }

}

2
感谢您的帮助!对我们帮助很大!上帝保佑。 - Tony
我尝试了你的解决方案,它可以工作。但是我无法获取所选值,我尝试使用combobox.SelectedItem.ToString(),但它没有返回预期的结果。你有什么想法吗?谢谢 - Bluety
1
抱歉Bluety,我两年来一直没有回复你,但我遇到了类似的问题,因为我的基础属性(字符串)与SelectedItem类型(我的Item类)不匹配,绑定从未发生。绑定到SelectedValue而不是SelectedItem解决了这个问题。 - Sean
6
很好的内容。但我觉得有些困惑,因为标题模板和项目模板都绑定到一个名为“Name”的属性上。如果将Item.Name属性重命名为(比如)Item.Description,那么在XAML中,标题模板将绑定到ListCollectionView中的隐式“Name”属性,而项目模板将绑定到“Description”。非常棒的示例-谢谢。 - Richard Moore
1
非常好的答案。将ItemSource绑定到ObservableCollection<Item>会锦上添花 :) - M Stoerzel
显示剩余3条评论

0

这里是对ASanch答案的改进,使其更加MVVM友好,您可以将其绑定到CollectionView。

视图模型:


namespace StackOverflow
{
    public class MainViewModel : INotifyPropertyChanged
    {

        public ObservableCollection<Item> Items { get; set; }
        public CollectionViewSource CollectionView { get; set; }


        public MainViewModel()
        {
            
            List<Item> items = new List<Item>();
            items.Add(new Item() { Name = "Item1", Category = "A" });
            items.Add(new Item() { Name = "Item2", Category = "A" });
            items.Add(new Item() { Name = "Item3", Category = "A" });
            items.Add(new Item() { Name = "Item4", Category = "B" });
            items.Add(new Item() { Name = "Item5", Category = "B" });            
            
            Items = new ObservableCollection<Item>(items);

            var view = new CollectionViewSource();
            view.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
            view.Source = Items;
            CollectionView = view;
        }
        
        public CollectionViewSource CollectionView { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

    }
    
    public class Item
    {
        public string Name { get; set; }
        public string Category { get; set; }
    }

}

XAML:

<Window x:Class="StackOverflow.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:StackOverflow"
        xmlns:uc="clr-namespace:StackOverflow.UserControls"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <StackPanel>
        <ComboBox ItemsSource="{Binding CollectionView.View}" DisplayMemberPath="Name">
            <ComboBox.GroupStyle>
                <GroupStyle/>
            </ComboBox.GroupStyle>
        </ComboBox>
    </StackPanel>
</Window>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接