简体   繁体   中英

WPF add specific button to ItemsControl ItemsPanel

I have an ItemsControl where I display a long list of objects. I display it in a wrappanel so the user does not need to scroll. Now i want to add a Button at the end of the list, so the user can add new objects. What would be the best way to do this?

Here is my 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>

one way i can suggest is to have 2 item templates, depending on their purpose.

here I created a class InventoryNewItem , derived from InventoryItem ( public class InventoryNewItem : InventoryItem {} , that is all). Type is used as a key for template selection from resourses

<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>

pros: separate templates and click handlers (or command bindings) for each template

cons: additional manipulations to keep InventoryNewItem at the last position in ItemsSource (you can't add, have to insert new elements)

my test 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);
<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>

As mentioned in this question , you can use CompositeCollection class to combine your collection with other controls or collections.

In this example I've added two buttons after CheckBox items:

<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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM