WPF 将特定按钮添加到 ItemsControl ItemsPanel

WPF add specific button to ItemsControl ItemsPanel

我有一个 ItemsControl,我在其中显示一长串对象。我将它显示在包装面板中,因此用户不需要滚动。现在我想在列表末尾添加一个按钮,以便用户可以添加新对象。执行此操作的最佳方法是什么?

这是我的 xaml:

<ItemsControl ItemsSource="{Binding Inventory}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Grid Width="300">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="30"/>
                    </Grid.ColumnDefinitions>
                    <Button Content="{Binding Name}"                        
                            MouseDoubleClick="CallEdit"/>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel MaxHeight="{Binding ElementName=window, Path=Height}"
                       Orientation="Vertical"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                                        
</ItemsControl>
<Grid>
  <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
  </Grid.RowDefinitions>
  <ItemsControl Grid.Row="0" ItemsSource="{Binding Inventory}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Grid Width="300">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition/>
                        <ColumnDefinition Width="30"/>
                    </Grid.ColumnDefinitions>
                    <Button Content="{Binding Name}"                        
                            MouseDoubleClick="CallEdit"/>
                </Grid>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel MaxHeight="{Binding ElementName=window, Path=Height}"
                       Orientation="Vertical"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>                                        
    </ItemsControl>
    <StackPanel Grid.Row="1" >
        <Button Content="Add"/>
    </StackPanel>
</Grid>

我可以建议的一种方法是使用 2 个项目模板,具体取决于它们的用途。

这里我创建了一个class InventoryNewItem,派生自InventoryItempublic class InventoryNewItem : InventoryItem {},仅此而已)。类型用作从资源中选择模板的键

<ItemsControl ItemsSource="{Binding Inventory}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type views:InventoryItem}">
            <StackPanel>
                <Grid >
                    <Button Content="{Binding Path=Name}" Click="ButtonBase_OnClick"/>
                </Grid>
            </StackPanel>
        </DataTemplate>

        <DataTemplate DataType="{x:Type views:InventoryNewItem}">
            <StackPanel>
                <Grid >
                    <Button Content="+" Background="Green" Click="Add_OnClick"/>
                </Grid>
            </StackPanel>
        </DataTemplate>                    
    </ItemsControl.Resources>

    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel MaxHeight="{Binding ElementName=window, Path=Height}" 
                       Orientation="Vertical"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

优点:为每个模板分离模板和点击处理程序(或命令绑定)

缺点:额外的操作将 InventoryNewItem 保留在 ItemsSource 的最后位置(您不能添加,必须插入新元素)

我的测试ItemsSource

var list = Enumerable.Range(1, 20)
              .Select(i => new InventoryItem {Name = i.ToString()})
              .Concat(new List<InventoryItem> {new InventoryNewItem()});
ItemsSource = new ObservableCollection<InventoryItem>(list);

如上所述 in this question, you can use CompositeCollection class 将您的集合与其他控件或集合结合起来。

在此示例中,我在 CheckBox 项之后添加了两个按钮:

<ItemsControl>
  <ItemsControl.ItemsSource>
    <CompositeCollection>
      <CollectionContainer Collection="{Binding Inventory}"/>
      <Button Margin="5,7,5,7" Padding="4,0" Content="CheckAll"/>
      <Button Margin="5,7,5,7" Padding="4,0" Content="UncheckAll"/>
    </CompositeCollection>
  </ItemsControl.ItemsSource>

  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <CheckBox Content="{Binding Label}"  
                IsChecked="{Binding IsVisible}"  
                IsEnabled="{Binding IsEnabled}" 
                Margin="5,7,5,7"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>