WPF筛选Datagrid组合框列

时间:2018-10-22 20:48:11

标签: c# wpf

首次发布。我是C#和WPF的新手。我花了超过15个小时来尝试解决这个问题,而我将退出并开始使用Windows Forms。我有一个(当前)三列的DataGrid,但是只有两列对此很重要,即Type和Subtype。我从XML文件中填充了大约15种类型,每种类型都有2-15个子类型。我正在尝试根据第一列中选​​择的内容来过滤(或填充)第二列。

我尝试在第二列上使用DynamicResource,但在下一行将覆盖它,并清除第一行的选择。我对绑定没有足够的了解,无法知道如何使它们特定于行。我已经在C#端创建了一个列表和一个集合,其中填充了所选类型的每个子类型(以及为每个可能的Type填充的另一对,甚至在我的类型集合中嵌入了一个子类型集合),但是我可以t弄清楚如何将其中任何一个添加到第二列的组合框项目源中,而不在每一行中都显示它们。

XAML:

 <DataGridComboBoxColumn Header="Type"
                            ItemsSource="{DynamicResource UnitTypeSource}"
                            SelectedValuePath="TypeString"
                            SelectedItemBinding="{Binding Path=TypeString, NotifyOnTargetUpdated=True}"
                            DisplayMemberPath="TypeString"
                            x:Name="colTypeUnit"/>
                        <DataGridTemplateColumn Header="Subtype">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <ComboBox
                                        ItemsSource="{Binding DataContext.AllSubtypes, RelativeSource={RelativeSource AncestorType=local:MainWindow}}"
                                        DisplayMemberPath="Name"
                                        />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>

希望对您有所帮助,甚至只是作为参考。

1 个答案:

答案 0 :(得分:0)

使用DataGrid和ComboBoxes可能会很快变得有点复杂,因此让我们一次跨一步,并进行一些解释。我已经为您提供了代码段中的完整类。

首先,我将坚持使用MVVM模型,并使用model-view-viewmmodel将数据绑定到DataGrid。视图模型将包含TypeSubType值列表以及行列表。我将将此行的模型类称为TypeModel

public class TypeModel
{
    public string Type { get; set; }
    public string SubType { get; set; }
}

我不知道您如何确定SubType对给定的Type有效,但是对于本示例,我将使用字典在视图模型中设置关系。

因此我们的视图模型可能类似于:

public class MainWindowViewModel
{
    public ObservableCollection<TypeModel> Collection { get; set; }

    public ObservableCollection<string> Type { get; set; }

    public Dictionary<string, List<string>> SubTypeCollection { get; set; }

    public MainWindowViewModel()
    {
        Collection = new ObservableCollection<TypeModel>();
        TypeCollection = new ObservableCollection<string>()
        {
            "Type 1","Type 2","Type 3"
        };

        SubTypeCollection = new Dictionary<string, List<string>>()
        {
            {
                TypeCollection[0], new List<string>()
                {
                    "Type 1 - Sub type 0",
                    "Type 1 - Sub type 1"
                }
            },
            {
                TypeCollection[1], new List<string>()
                {
                    "Type 2 - Sub type 0",
                    "Type 2 - Sub type 1",
                    "Type 2 - Sub type 2",
                    "Type 3 - Sub type 3",
                }
            },
            {
                TypeCollection[2], new List<string>()
                {
                    "Type 3 - Sub type 0",
                    "Type 3 - Sub type 1",
                    "Type 3 - Sub type 2",
                }
            }
        };
    }
}

现在让我们设置(初始)视图(稍后将添加到该视图):

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow"
        Width="600"
        Height="500">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <DataGrid
            AutoGenerateColumns="False"
            ItemsSource="{Binding Collection}">
            <DataGrid.Columns>
                <DataGridComboBoxColumn
                    Header="Type"
                    SelectedItemBinding="{Binding Type, UpdateSourceTrigger=PropertyChanged}"> <!-- property changed so we get the change right after we select-->
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.TypeCollection}" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>

            <DataGridComboBoxColumn
                Header="Sub Type"
                SelectedItemBinding="{Binding SubType}">
                <!-- How do we bind to the ItemSource based on the selected type?-->
            </DataGridComboBoxColumn>
        </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

所以您的基本问题是如何填写该注释掉的部分。

执行此操作的方法可能很多,在我看来,最简单的方法是使用带有两个绑定的IMultiValueConverter

  1. 选定的Type字符串
  2. 字典TypeCollection

所以该类看起来像这样(您真的可以将其用于所有stringlist<string>的转换):

public class TypeToSubTypesConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null) return null;

        if (values[0] == null || values[0] == DependencyProperty.UnsetValue) return null;
        var type = values[0].ToString();

        if (values[1] == null || values[1] == DependencyProperty.UnsetValue) return null;
        var subTypeList = values[1] as Dictionary<string, List<string>>;

        if (subTypeList == null) return null;


        return subTypeList[type];

    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }
}

现在最后的步骤是:

  1. 将转换器资源添加到视图中
  2. 为第二列组合框的value的每个setter的{​​{1}}属性添加多重绑定

因此,完整的.xaml如下所示:

ItemsSource