简体   繁体   English

WPF XAML 组合框主从

[英]WPF XAML Comboboxes Master Detail

I'm new to WPF and have a obviously very simple or basic problem which I failed to solve even though I have read for hours to find a solution.我是 WPF 的新手,有一个明显非常简单或基本的问题,尽管我已经阅读了几个小时以找到解决方案,但我未能解决。 Here it is: I have two Comboboxes, a master and a detail combobox. The master has two entries: "Option 1" and "Option 2".这是:我有两个 Comboboxes,一个 master 和一个 detail combobox。master 有两个条目:“Option 1”和“Option 2”。 The detail combobox should have two entries "Value 1" and "Value 2" when "Option 1" is selected or "Value A" and "Value B" when "Option 2" is selected in the master combobox. I think that should be possible with pure XAML.详细信息combobox应该在选择“选项1”时具有两个条目“值1”和“值2”或“值A”和“值A”和“ value B”当Master 8combobox中选择“选项2”。我认为应该是可以使用纯 XAML。

Basically I tried to assign a dictionary collection to each of the comboboxes and tried to reference (bind) the master list via the "Key".基本上,我尝试为每个组合框分配一个字典集合,并尝试通过“键”引用(绑定)主列表。 Following is my xaml-code so far (I have withdrawn all my bind-attempts)到目前为止,以下是我的 xaml 代码(我已撤回所有绑定尝试)

<Window x:Class="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:Test"
        mc:Ignorable="d"
        xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="221" Width="457">
    <Window.Resources>
        <col:ArrayList x:Key="masterlist">
            <col:DictionaryEntry Key="option1" Value="Option one"/>
            <col:DictionaryEntry Key="option2" Value="Option two" />
        </col:ArrayList>

        <col:ArrayList x:Key="detaillist">
            <col:DictionaryEntry Key="option1" Value="Value 1"/>
            <col:DictionaryEntry Key="option1" Value="Value 2"/>
            <col:DictionaryEntry Key="option2" Value="Value A"/>
            <col:DictionaryEntry Key="option2" Value="Value B"/>
        </col:ArrayList>
    </Window.Resources>

    <Grid Margin="0,0,0,29">
        <ComboBox x:Name="ComboboxMaster" HorizontalAlignment="Left" Margin="33,39,0,0" VerticalAlignment="Top" Width="120"
            ItemsSource ="{StaticResource masterlist}"
            DisplayMemberPath="Value"
            SelectedValuePath="Key"
            IsSynchronizedWithCurrentItem="True"
            SelectedIndex="0">

        </ComboBox>
        <ComboBox x:Name="ComboboxDetail" HorizontalAlignment="Center" Margin="0,39,0,0" VerticalAlignment="Top" Width="120"
            ItemsSource ="{StaticResource detaillist}"
            DisplayMemberPath="Value"
            SelectedValuePath="Key"
            SelectedIndex="0">
        </ComboBox>
        <Label x:Name="labelMasterKey" HorizontalAlignment="Left" Margin="33,75,0,0" VerticalAlignment="Top" Width="120"
               Content="{Binding ElementName=ComboboxMaster, Path=SelectedValue}"/>
        <Button Content="Close" HorizontalAlignment="Left" Margin="33,123,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.071,-0.349" Click="Button_Click" Height="26" Width="64"/>
    </Grid>
</Window>

Your help for a dummy like me is appreciated感谢您对像我这样的假人的帮助

Split the detail list into two lists and assign the appropriate one in the Setter of a DataTrigger on the SelectedValue of the master ComboBox:将详细列表拆分为两个列表,并在主 ComboBox 的 SelectedValue 上的 DataTrigger 的 Setter 中分配适当的一个:

<Window.Resources>
    <col:ArrayList x:Key="masterlist">
        <col:DictionaryEntry Key="option1" Value="Option one"/>
        <col:DictionaryEntry Key="option2" Value="Option two" />
    </col:ArrayList>

    <col:ArrayList x:Key="detaillist1">
        <col:DictionaryEntry Key="option1" Value="Value 1"/>
        <col:DictionaryEntry Key="option2" Value="Value 2"/>
    </col:ArrayList>

    <col:ArrayList x:Key="detaillist2">
        <col:DictionaryEntry Key="option1" Value="Value A"/>
        <col:DictionaryEntry Key="option2" Value="Value B"/>
    </col:ArrayList>
</Window.Resources>

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <ComboBox x:Name="ComboboxMaster" Grid.Column="0" Width="120" Margin="20"
              ItemsSource="{StaticResource masterlist}"
              DisplayMemberPath="Value"
              SelectedValuePath="Key"
              SelectedIndex="0"/>

    <ComboBox x:Name="ComboboxDetail" Grid.Column="1" Width="120" Margin="20"
              DisplayMemberPath="Value"
              SelectedValuePath="Key">
        <ComboBox.Style>
            <Style TargetType="ComboBox">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SelectedValue,
                                                   ElementName=ComboboxMaster}"
                                 Value="option1">
                        <Setter Property="ItemsSource"
                                Value="{StaticResource detaillist1}"/>
                        <Setter Property="SelectedValue"
                                Value="option1"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding SelectedValue,
                                                   ElementName=ComboboxMaster}"
                                 Value="option2">
                        <Setter Property="ItemsSource"
                                Value="{StaticResource detaillist2}"/>
                        <Setter Property="SelectedValue"
                                Value="option1"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ComboBox.Style>
    </ComboBox>
</StackPanel>

Another possibility would be using the MVVM pattern.另一种可能性是使用 MVVM 模式。 THis brings you to more flexibility with your data and seperating the data from your view.这使您可以更灵活地处理数据并将数据与视图分开。

First you have to create a new ViewModel class like this:首先,您必须像这样创建一个新的 ViewModel class:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private Dictionary<string, List<string>> _comboboxData;
    private string _selectedItem1;
    private string _selectedItem2;

    public event PropertyChangedEventHandler PropertyChanged;

    public MainWindowViewModel()
    {
        _comboboxData = new Dictionary<string, List<string>>
        {
            {"option1", new List<string>{"Value 1", "Value 2"}},
            {"option2", new List<string>{"Value A", "Value B"}},
        };
        _selectedItem1 = "option1";
        _selectedItem2 = _comboboxData[SelectedItem1][0];
    }

    public string SelectedItem1
    {
        get => _selectedItem1;
        set
        {
            if (value == _selectedItem1) return;
            _selectedItem1 = value;
            RaisePropertyChanged();
            RaisePropertyChanged(nameof(Combobox2Data));
            SelectedItem2 = _comboboxData[SelectedItem1][0]
        }
    }

    public string SelectedItem2
    {
        get => _selectedItem2;
        set
        {
            if (value == _selectedItem2) return;
            _selectedItem2 = value;
            RaisePropertyChanged();
        }
    }

    public ObservableCollection<string> Combobox1Data => new ObservableCollection<string>(_comboboxData.Keys);

    public ObservableCollection<string> Combobox2Data =>
        new ObservableCollection<string>(_comboboxData[_selectedItem1]);

    private void RaisePropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

with this your WPF MainWindow.xaml will look like this:这样你的 WPF MainWindow.xaml 将如下所示:

<Window x:Class="WpfTest.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:WpfTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Grid Margin="0,0,0,29">
        <ComboBox x:Name="ComboboxMaster" HorizontalAlignment="Left" Margin="33,39,0,0" VerticalAlignment="Top" Width="120"
                  ItemsSource ="{Binding Combobox1Data}"
                  SelectedItem="{Binding SelectedItem1}">
        </ComboBox>
        <ComboBox x:Name="ComboboxDetail" HorizontalAlignment="Center" Margin="0,39,0,0" VerticalAlignment="Top" Width="120"
                  ItemsSource="{Binding Combobox2Data}"
                  SelectedItem="{Binding SelectedItem2}">
        </ComboBox>
        <Label x:Name="labelMasterKey" HorizontalAlignment="Left" Margin="33,75,0,0" VerticalAlignment="Top" Width="120"
               Content="{Binding SelectedItem2}"/>
        <Button Content="Close" HorizontalAlignment="Left" Margin="33,123,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.071,-0.349" Height="26" Width="64"/>
    </Grid>
</Window> 

With this you may change your data dictionary with more values eg for ComboBox 1 (Keys) or more values for each keyed List (Values) only at beginning of ViewModel class without other changes anywhere有了这个,您可以使用更多值更改数据字典,例如 ComboBox 1(键)或仅在 ViewModel class 开头的每个键控列表(值)的更多值,而无需任何其他更改

«Pure» XAML: «纯» XAML:

    <Window.Resources>
        <col:ArrayList x:Key="masterlist">
            <col:DictionaryEntry Key="Option one">
                <col:DictionaryEntry.Value>
                    <col:ArrayList>
                        <col:DictionaryEntry Key="option1" Value="Value 1"/>
                        <col:DictionaryEntry Key="option1" Value="Value 2"/>
                    </col:ArrayList>
                </col:DictionaryEntry.Value>
            </col:DictionaryEntry>
            <col:DictionaryEntry Key="Option one">
                <col:DictionaryEntry.Value>
                    <col:ArrayList>
                        <col:DictionaryEntry Key="option2" Value="Value A"/>
                        <col:DictionaryEntry Key="option2" Value="Value B"/>
                    </col:ArrayList>
                </col:DictionaryEntry.Value>
            </col:DictionaryEntry>
        </col:ArrayList>

    </Window.Resources>

    <Grid Margin="0,0,0,29">
        <ComboBox x:Name="ComboboxMaster" HorizontalAlignment="Left" Margin="33,39,0,0" VerticalAlignment="Top" Width="120"
            ItemsSource ="{StaticResource masterlist}"
            DisplayMemberPath="Key"
            SelectedIndex="0">

        </ComboBox>
        <ComboBox x:Name="ComboboxDetail" HorizontalAlignment="Center" Margin="0,39,0,0" VerticalAlignment="Top" Width="120"
            ItemsSource ="{Binding SelectedItem.Value, ElementName=ComboboxMaster}"
            DisplayMemberPath="Value"
            SelectedIndex="0">
        </ComboBox>
        <Label x:Name="labelMasterKey" HorizontalAlignment="Left" Margin="33,75,0,0" VerticalAlignment="Top" Width="120"
               Content="{Binding ElementName=ComboboxDetail, Path=SelectedItem.Value}"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM