从属列表框

Dependent ListBox

我正在尝试编写一个包含两个列表框的代码,其中第二个显示的内容取决于第一个中选择的内容,但我在阅读第一个中选择的内容时遇到困难,进行此切换(这是我使用 WPF 的第一个代码)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;

namespace BMFinder
{
    /// <summary>
    /// Interação lógica para MainWindow.xam
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            List<string> Itens = new List<string>();
            Itens.Add("Armas");
            Itens.Add("Capacete");
            Itens.Add("Amadura");
            Itens.Add("Botas");

            List1.ItemsSource = Itens;

            List<string> Tipo = new List<string>();
            Tipo.Add("Couro");
            Tipo.Add("Placa");
            Tipo.Add("Tecido");

            List<string> Armas = new List<string>();
            Armas.Add("Espadas");
            Armas.Add("Arcos");
            Armas.Add("Lanças");
            Armas.Add("Bestas");

            string selecionado = List1.SelectedItem.ToString();
            if (selecionado == "Armas")
            {
                List2.Items.Clear();
                List2.ItemsSource = Armas;
            }
            else
            {
                List2.Items.Clear();
                List2.ItemsSource = Tipo;
            }

        }
    }
}

在我看来,您需要更多地研究一下这些类型的程序通常是如何工作的。

程序被分成称为“方法”的代码段。每个方法 运行s 一直到最后。 public MainWindow() 是一种特殊类型的方法,称为 constructor。构造函数 运行 每当创建对象时。本例中的“对象”是您的 MainWindow.

public MainWindow() 是 window 中将 运行 的第一位代码。它会 运行 甚至显示 window 之前。


string selecionado = List1.SelectedItem.ToString();
在设置项目列表后立即执行,但它失败了,因为 还没有 选择的项目。 window 甚至还没有显示。用户没有机会进行选择。

要完成您的尝试,您需要将代码分成多个方法,这些方法将在不同时间 运行。一开始会设置MainWindow。并在选择更改后设置 List2.ItemsSource

运行 不同时间的方法最好使用 events. Specifically, you can use the ListBox.SelectionChanged 事件来完成。

在WPF中,也有数据绑定,只是稍微高级一点,这里就不多说了。

使用可观察集合来通知集合中的更改。实现方式有很多种,其中一种方式如下。

Usercontrol.xaml

<UserControl x:Class="WpfApplication1.UserControl2"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:WpfApplication1"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Grid.Resources>

        <!--Base Collection contains keys to decide loading of child collection-->
        <local:Itens x:Key="baseCollection"/>
        
        <!--Child collections-->
        <local:Tipo x:Key="tipo"/>
        <local:Armas x:Key="armas"/>
    </Grid.Resources>
    
    <Grid.RowDefinitions>
        <!--Base collection row-->
        <RowDefinition/>
        <!--Child collection container row-->
        <RowDefinition/>
    </Grid.RowDefinitions>

    <!--Base collection-->
    <ListBox Grid.Row="0" 
             ItemsSource="{StaticResource baseCollection}"
             Name="BaseList"/>
    
    <!--Child collection container-->
    <ListBox Grid.Row="1">
        <!--Data trigger to monitor the change in selected item in listbox baselist
        and load the child collection accordingluy-->
        <ListBox.Style>
            <Style TargetType="ListBox">
                
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=BaseList,Path=SelectedItem}" Value="Tipo">
                        <Setter Property="ItemsSource" Value="{StaticResource tipo}"/>
                    </DataTrigger>

                    <DataTrigger Binding="{Binding ElementName=BaseList,Path=SelectedItem}" Value="Armas">
                        <Setter Property="ItemsSource" Value="{StaticResource armas}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ListBox.Style>
    </ListBox>
</Grid>

usercontrol.cs

public partial class UserControl2 : UserControl
{
    public UserControl2()
    {
        InitializeComponent();
    }
}

public class Itens : ObservableCollection<string>
{
    public Itens()
    {
        Add("Armas");
        Add("Capacete");
        Add("Amadura");
        Add("Botas");
        Add("Tipo");
    }
}

public class Tipo : ObservableCollection<string>
{
    public Tipo()
    {
        Add("Couro");
        Add("Placa");
        Add("Tecido");
    }
}

public class Armas : ObservableCollection<string>
{
    public Armas()
    {
        Add("Espadas");
        Add("Arcos");
        Add("Lanças");
        Add("Bestas");
    }
}

最简单的解决方案,不使用数据绑定。

MainWindows.xaml.cs

public partial class MainWindow : Window
{
    private List<string> Tipo { get; set; }
    private List<string> Armas { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        List1.ItemsSource = new List<string>
        {
            "Armas",
            "Capacete",
            "Amadura",
            "Botas"
        }

        this.Tipo = new List<string>
        {
            "Couro",
            "Placa",
            "Tecido"
        }

        this.Armas = new List<string>
        {
            "Espadas",
            "Arcos",
            "Lanças",
            "Bestas"
        }
    }

    private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var selector = sender as Selector;
        var selectedItem = selector.SelectedItem as string;
        switch (selectedItem)
        {
            case "Armas":
              selector.ItemsSource = this.Armas; break;
            default:
              selector.ItemsSource = this.Tipo; break;
        }
    }
}

MainWindow.xaml

<Window>
  <ListBox x:Name="List1" SelectionChanged="OnSelectionChanged" />
</Window>

进一步阅读:

Data binding overview in WPF,
Routed Events Overview