C# 基于DataGrid项更改DataGridComboxColumn项源

C# 基于DataGrid项更改DataGridComboxColumn项源,c#,wpf,mvvm,combobox,C#,Wpf,Mvvm,Combobox,在我的应用程序中,我使用C#、WPF,并且遵循MVVM模式 我正在努力实现以下目标: 我有一个DataGrid,它ItemSource在我的ViewModel中的Collection上绑定MyObject有两个enum属性,即TypeA和TypeB(TypeA是与TypeB不同的枚举类型) 数据网格的每一行都有一个组合框,用户可以通过选择一个可用值来更改TypeB值。用户无法更改类型A。然而,TypeB的可用值基于TypeA的值 <DataGridTemplateColumn Header

在我的应用程序中,我使用C#、WPF,并且遵循MVVM模式

我正在努力实现以下目标:

我有一个
DataGrid
,它
ItemSource
在我的ViewModel中的
Collection
上绑定
MyObject
有两个
enum
属性,即TypeA和TypeB(TypeA是与TypeB不同的枚举类型)

数据网格的每一行都有一个
组合框
,用户可以通过选择一个可用值来更改TypeB值。用户无法更改类型A。然而,TypeB的可用值基于TypeA的值

<DataGridTemplateColumn Header="Type B">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox SelectedItem="{Binding TypeB, UpdateSourceTrigger=PropertyChanged}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Converter={StaticResource DescriptionConverter}}"/>
                    </DataTemplate>
                 </ComboBox.ItemTemplate>
             </ComboBox>
         </DataTemplate>
     </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
和视图模型

public ICollectionView AvailableTypeB
{
    get
    {
        ObservableCollection<TypeB> availableTypeB = new ObservableCollection<TypeB>((TypeB[])Enum.GetValues(typeof(TypeB)));

        // Here based on the TypeA property of the SelectedRow in the grid 
        // I am populating the availableTypeB collection with the needed values based on the aforementioned rules

        return CollectionViewSource.GetDefaultView(availableTypeB);
    }
}
公共ICollectionView可用PEB
{
得到
{
ObservableCollection availableTypeB=新的ObservableCollection((TypeB[])Enum.GetValues(typeof(TypeB));
//此处基于网格中SelectedRow的TypeA属性
//我正在根据上述规则使用所需的值填充availableTypeB集合
返回CollectionViewSource.GetDefaultView(availableTypeB);
}
}
*
SelectedRow
是一个绑定到数据网格的SelectedItem的项

我还尝试过,而不是每次创建集合并返回默认视图,而是为TypeB枚举项创建一次CollectionView,每次都基于
SelectedRow
应用一个新的
过滤器

这种方法的问题是,当AvailableTypeB发生变化时,ComboBox的SelectedItem为null,SelectedItem不再是它的一部分。我试图改变绑定
模式
IsSynchronizedWithCurrentItem
,但没有成功

  • 我尝试的第二种方法是在ComboBox.Loaded事件上填充ComboBox.ItemsSource。这可以通过几种方式实现,我尝试的是

    -。具有已加载的事件,并且在代码隐藏中执行
    ComboBox.ItemsSource=

    -。使用交互性引用以使用命令而不是加载的事件

    它们都在某种程度上“打破”了MVVM模式。使用交互性程序集时,我必须将
    组合框
    控件传递给模型,以便访问其数据源,这直接违反了MVVM

    我知道还有第三种方法,即使用我尚未尝试过的附加行为

  • 将可用TypeB值的集合作为my
    MyObject
    类中的唯一get属性。这是一个更干净的解决方案,但是它使我的
    MyObject
    类不那么通用。在我的程序的某些部分中,用户可以更改上述规则不适用的
    TypeB
    值,这就是我希望避免这种方法的原因

  • 注意1:由于这是一篇很长的文章,我试图将代码样本保持在最小。如果您认为缺少某些详细信息,请询问他们,我将进行编辑/更新。

    注2:我知道问题的某些部分可能是“基于意见的”,也许codeReview是一个更好的地方。

    我建议您按照选项3中的方法,将其命名为
    TypeBListFiltered
    或其他(基于
    SelectedTypeA
    属性的过滤器),并以
    TypeBList
    的形式公开一个单独的完整的TypeB列表。消费者使用合适的列表。这并不是“不那么通用”。但是您也可以编写一个ValueConverter,它接受一个TypeA参数,并返回一个经过筛选的TypeB值集合。你知道,你的选择2是个坏主意。A.fil@EdPlunkett说实话,我喜欢转换器(我也这么认为,但我没有提到)。然而,我的意见是,转换器不打算以这种方式使用。顾名思义,它们是在转换值,而不是过滤值。从另一个角度看,你可以说过滤是一种转换。没错,你通常认为转换器转换标量值,而不是将未过滤的集合转换为过滤的集合。但对于一个小的不断收集,我并不认为这是滥用机制。它不会产生任何难看的惊喜,也不会在运行时淹没您。如果我看到
    ItemsSource=“{Binding SelectedTypeA,Converter={StaticResource TypeBFilterConverter}}”
    ,我就不必浪费时间猜测我在看什么了。
    <ComboBox ItemsSource="{Binding TypeBAvailable}"
    
    public ICollectionView AvailableTypeB
    {
        get
        {
            ObservableCollection<TypeB> availableTypeB = new ObservableCollection<TypeB>((TypeB[])Enum.GetValues(typeof(TypeB)));
    
            // Here based on the TypeA property of the SelectedRow in the grid 
            // I am populating the availableTypeB collection with the needed values based on the aforementioned rules
    
            return CollectionViewSource.GetDefaultView(availableTypeB);
        }
    }