【问题标题】:How to send an ItemControl Item's location for nested collections如何为嵌套集合发送 ItemsControl Items 位置
【发布时间】:2018-11-27 13:17:35
【问题描述】:

我有一个绑定到ObservableCollection<ObservableCollection<BookModel>> 的ItemControl。最深的 ItemControl 中的每个项目都有一个按钮。我实现了一个每次单击按钮时都会触发的命令。
我的问题是我不知道应该将哪个参数传递给执行方法才能知道哪个 Item 触发了命令。意思是,如果按钮用作“添加图书”按钮,我想知道应该在哪里插入 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
}

【问题讨论】:

  • 您只是想找到插入新书的位置吗?或者这是一个层次结构,您需要知道要将图书添加到的父级?
  • 你可以只传递“这个”吗? CommandParameter="{Binding . }" ?
  • @KevinCook 不确定我是否理解您的问题。我想知道将新书添加到哪一列以及将其插入到哪一行,这应该会影响Iobservable&lt;Iobservable&lt;BookModel&gt;
  • 只是想看看为什么你需要知道这一行。如果您需要以网格格式显示它,为什么不直接使用 > 然后使用 wrappanel。这就是为什么我要询问层次结构。
  • @RandRandom 当然你可以为命令参数指定一个绑定——我已经做了将近十年了

标签: c# wpf xaml datatemplate itemscontrol


【解决方案1】:

您可以使用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.");
    }
}

【讨论】:

  • 我尝试了您的解决方案,但它仅提供每列中的行索引,所以我仍然无法确定哪个项目触发了命令...我所做的是将AlternationCount 设置为外部 DataTemplate 的 ItemsControl (DataTemplate_level1) 并将AlternationIndex 作为命令参数传递。这是实施您的解决方案的正确方法吗?
  • 我已经用嵌套集合的示例扩展了我的答案。
  • 抱歉延迟回复。您的解决方案完美运行。我不得不将 Convert 方法的语法更改为:return String.Format("{0} {1}", values[0], values[1]);。感谢您提供快速而优雅的解决方案。
猜你喜欢
  • 2012-12-08
  • 1970-01-01
  • 2015-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-04
  • 2020-02-21
相关资源
最近更新 更多