通过 C# 访问 ListView 内的组合框

Access ComboBoxes inside a ListView via C#

我有一个包含 2 列的 ListView。第一列是一个简单的字符串。第二个模板设置为单个 ComboBox。行数和 ComboBox 的数量未知。

我的XAML:

<ListView Grid.Row="0" Name="listView" IsSynchronizedWithCurrentItem="True" SelectionMode="Single" Margin="10" ItemsSource="{Binding ImportColumns}">
            <ListView.Resources>
                <local:ListFilterMultiConverter x:Key="listFilterConverter" />
            </ListView.Resources>

            <ListView.View>
                <GridView AllowsColumnReorder="False">

                    <GridViewColumn Header="File column" DisplayMemberBinding="{Binding FileColumnHeader}"/>

                    <GridViewColumn Header="Worksheet column">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>

                                <ComboBox VerticalAlignment="Center" DataContext="{Binding DataContext,RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" SelectionChanged="ComboBox_SelectionChanged" SelectedIndex="0" >
                                    <ComboBox.ItemsSource>
                                        <MultiBinding Converter="{StaticResource listFilterConverter}">
                                            <Binding Path="ListOfWorksheetColumns.UnselectedWorksheetColumns"/>
                                            <Binding RelativeSource="{RelativeSource Self}"/>
                                        </MultiBinding>
                                    </ComboBox.ItemsSource>
                                </ComboBox>

                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>

                </GridView>
            </ListView.View>

        </ListView>

我需要知道第二列的组合框中的内容,以便第一列中的字符串可以与相应组合框的值相关联。问题是我只引用了第一列中的项目。

我的导入列class:

public class ImportColumn : BaseViewModel
{
    public string FileColumnHeader { get; set; }
}

BaseViewModel class:

public class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
}

像您在此处所做的那样绑定 DataContext 是错误的,因为绑定的 DataContext 将是 ComboBox 上任何其他绑定的默认源。这会妨碍您,因为您希望能够绑定到真实数据上下文的属性,即行对象 ImportColumn

我们可以通过在多重绑定中使用与 DataContext 相同的 RelativeSource 来解决这个问题,这样我们就可以自由地将 ComboBox.SelectedItem 绑定到 ImportColumn 上的 FileColumnHeader那一行。

<DataTemplate>
    <ComboBox 
        VerticalAlignment="Center" 
        SelectedItem="{Binding FileColumnHeader}"
        SelectionChanged="ComboBox_SelectionChanged"
        >
        <ComboBox.ItemsSource>
            <MultiBinding Converter="{StaticResource listFilterConverter}">
                <Binding 
                    Path="DataContext.ListOfWorksheetColumns.UnselectedWorksheetColumns"
                    RelativeSource="{RelativeSource AncestorType={x:Type ListView}}"
                    />
                <Binding RelativeSource="{RelativeSource Self}"/>
            </MultiBinding>
        </ComboBox.ItemsSource>
    </ComboBox>
</DataTemplate>

我在评论中了解到,SelectionChanged 处理程序正在用于其他可以并且可以说应该在 MVVM 中完成的事情,但它有点复杂。

为了使其正常工作,ImportColumn.FileColumnHeader 需要在其值更改时正确引发 PropertyChanged。由于您 ImportColumn 继承自 BaseViewModel,我猜您可能为了简洁而省略了该细节。

有点跑题:我相信您的 listFilterConverter 应该将 ComboBox 以外的其他参数作为其第二个参数。无论它从 ComboBox 获得什么属性,您都应该只绑定这些属性。如果消费者需要将其参数包装在 ComboBox 中,则转换器很难重用。但这不是现在的本质。