如何发送嵌套集合的 ItemsControl 项目位置

How to send an ItemControl Item's location for nested collections

我有一个绑定到 ObservableCollection<ObservableCollection<BookModel>> 的 ItemControl。最深的 ItemControl 中的每个项目都有一个按钮。我实现了一个每次单击按钮时都会触发的命令。
我的问题是我不知道应该将哪个参数传递给执行方法才能知道哪个 Item 触发了命令。意思是,如果按钮用作 "Add Book" 按钮,我想知道我应该在哪里插入 BookModel 对象

<UserControl.Resources>
<DataTemplate x:Key="BooksViewTemplate">
    <StackPanel>
        <TextBlock>
            <!-- This is where I bind data to the BookModel -->
        </TextBlock>
        <Button x:Name="AddNewBook"
                Command="{Binding ElementName=LayoutRoot, Path = DataContext.AddBookCommand}"
                <!-- CommandParameter=  -->
        />
    </StackPanel>
</<DataTemplate>

<DataTemplate x:Key="DataTemplate_level1">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource BooksViewTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical">
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </StackPanel>
</DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot">
<ItemsControl ItemsSource="{Binding Books}" ItemTemplate="{DynamicResource DataTemplate_level1}" DataContext="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

public ICommand AddBookCommand
{
    get
    {
        return _addBookCommnad ?? (_addBookCommand = new CmandHandler<object>((par) => AddBookAction(par), _canExecute));
    }
}

public void AddBookAction(object obj)
{
    //This is where I want to add a new BookModel to the 
    IObservableCollection<IObservableCollection<BookModel>> at the location 
    given by the pressed button
}

您可以使用 AlternationIndex 属性 来获取索引。只需将 ItemsControl 中的 AlternationCount 设置为 int.MaxValue

<ItemsControl ItemsSource="{Binding yourcollection}" AlternationCount="2147483647">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

如果您将一个项目作为 CommandParameter 传递并在您的集合中搜索,那么它将起作用,如果您在集合中没有重复引用,否则它将失败(您不会知道你应该采取哪个实例)。

对于嵌套集合,您可以通过以下方式访问索引:

<ItemsControl ItemsSource="{Binding ColOfCol}" AlternationCount="2147483647">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding }" AlternationCount="2147483647">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding Converter="{StaticResource multivalcnv}">
                                    <Binding Path='(ItemsControl.AlternationIndex)' RelativeSource="{RelativeSource AncestorType=ContentPresenter, AncestorLevel=2}"></Binding>
                                    <Binding Path='(ItemsControl.AlternationIndex)' RelativeSource="{RelativeSource AncestorType=ContentPresenter, AncestorLevel=1}"></Binding>
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

public class MultValConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length == 2)
        {
            //return (values[0], values[1]); //For the ViewModel
            return (values[0], values[1]).ToString(); //For the UI example
            }
        else
            return Binding.DoNothing;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException("It's a one way converter.");
    }
}