none
多个ListBox实现层级联动选择 RRS feed

  • 问题

  • 比如:有3个ListBox, 第一个显示国家,第二个显示省份,第三个显示该省有多少人?

    数据源为同一份,有一个国家列表,每个国家下面有省份列表,每个省份下面有人列表

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public class Province
    {
        public string Name { get; set; }
    
        public ObservableCollection<Person> Persons { get; set; }
    }
    
    public class Country
    {
        public string Name { get; set; }
    
        public ObservableCollection<Province> Provinces { get; set; }
    }
    
    public class CountryList : ObservableCollection<Country>
    {
        public CountryList()
        {
            Country China = new Country
            {
                Name = "中国",
                Provinces = new ObservableCollection<Province>
                {
                    new Province
                    {
                        Name ="北京",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "中国-北京-p0", Age = 14},
                            new Person { Name = "中国-北京-p1", Age = 67},
                        }
                    },
    
                    new Province
                    {
                        Name="上海",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "中国-上海-p0", Age = 43},
                            new Person { Name = "中国-上海-p1", Age = 39},
                            new Person { Name = "中国-上海-p2", Age = 12},
                        }
                    },
    
                    new Province
                    {
                        Name="广东",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "中国-广东-p0", Age = 78},
                            new Person { Name = "中国-广东-p1", Age = 3},
                            new Person { Name = "中国-广东-p2", Age = 27},
                        }
                    }
                }
            };
    
            Country USA = new Country {
                Name = "USA",
                Provinces = new ObservableCollection<Province>
                {
                    new Province
                    {
                        Name ="USA-1",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "美国-1-p0", Age = 14},
                            new Person { Name = "美国-1-p1", Age = 67},
                        }
                    },
    
                    new Province
                    {
                        Name="USA-2",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "美国-2-p0", Age = 43},
                            new Person { Name = "美国-2-p1", Age = 39},
                            new Person { Name = "美国-2-p2", Age = 12},
                        }
                    },
    
                    new Province
                    {
                        Name="USA-3",
                        Persons = new ObservableCollection<Person>
                        {
                            new Person { Name = "美国-3-p0", Age = 78},
                        }
                    }
                }
            };
    
            this.Add(China);
            this.Add(USA);
        }
    }
    <Window x:Class="CollectionViewTest2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:CollectionViewTest2"
            mc:Ignorable="d"
            Title="MainWindow" Height="400" Width="800">
    
        <Window.Resources>
            <local:CountryList x:Key="Countrys"/>
    
            <CollectionViewSource x:Key="CountrysView" Source="{StaticResource Countrys}"/>
    
            <DataTemplate x:Key="PersonsDataTemplate">
                <StackPanel Height="50" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Center">
                    <TextBlock Height="50" Text="{Binding Name}"/>
                    <TextBlock Height="50" Margin="20,0,0,0" Text="{Binding Age}"/>
                </StackPanel>
            </DataTemplate>
        </Window.Resources>
        
        <Grid>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="2*"/>
                </Grid.ColumnDefinitions>
                <ListBox Name="lb1"
                         HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                         Margin="10" FontSize="30"
                         DisplayMemberPath="Name"
                         ItemsSource="{Binding Source={StaticResource CountrysView}}"/>
    
                <ListBox Name="lb2" Grid.Column="1"
                         HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                         Margin="10" FontSize="30"
                         DisplayMemberPath="Name"
                         ItemsSource="{Binding Path=Provinces, Source={StaticResource CountrysView}}"/>
    
                <ListBox Name="lb3" Grid.Column="2"
                         Margin="10" FontSize="30"
                         HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                         ItemTemplate="{StaticResource PersonsDataTemplate}"
                         ItemsSource="{Binding Path=Provinces/Persons, Source={StaticResource CountrysView}}"/>
            </Grid>
        </Grid>
    </Window>

    目前只有第一级和第二系能联动,第3级不行。



    • 已编辑 oneonce 2017年8月18日 1:04
    2017年8月18日 1:00

答案

  • 这样也可以:

    <ListBox Name="lb3" Grid.Column="2"
                Margin="10" FontSize="30"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                ItemsSource="{Binding SelectedItem.Persons, ElementName=lb2}"/>
    非常感谢~


    2017年8月18日 2:53
  • Hi,

    你可以尝试处理第二个ListBox的SelectionChanged事件。

     private void SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                ListBox listbox = sender as ListBox;
               
                if (listbox != null && listbox.Name == "lb2")
                {
                    Province pro = (Province)listbox.SelectedItem;
                    if (pro != null)
                    {
                        lb3.ItemsSource = lb2.ItemsSource.Cast<Province>().Where(p => p.Name == pro.Name).SelectMany(a => a.Persons);
                    }
                    else
                    {
                        if(listbox.ItemsSource.Cast<Province>().Count()!=0)
                        listbox.SelectedIndex = 0;
                    }
                }
            }

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • 已标记为答案 oneonce 2017年8月18日 2:52
    2017年8月18日 2:31
    版主

全部回复

  • Hi,

    你可以尝试处理第二个ListBox的SelectionChanged事件。

     private void SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                ListBox listbox = sender as ListBox;
               
                if (listbox != null && listbox.Name == "lb2")
                {
                    Province pro = (Province)listbox.SelectedItem;
                    if (pro != null)
                    {
                        lb3.ItemsSource = lb2.ItemsSource.Cast<Province>().Where(p => p.Name == pro.Name).SelectMany(a => a.Persons);
                    }
                    else
                    {
                        if(listbox.ItemsSource.Cast<Province>().Count()!=0)
                        listbox.SelectedIndex = 0;
                    }
                }
            }

    Best Regards,

    Bob


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • 已标记为答案 oneonce 2017年8月18日 2:52
    2017年8月18日 2:31
    版主
  • 这样也可以:

    <ListBox Name="lb3" Grid.Column="2"
                Margin="10" FontSize="30"
                HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                ItemsSource="{Binding SelectedItem.Persons, ElementName=lb2}"/>
    非常感谢~


    2017年8月18日 2:53