2010-01-21 3 views
1

J'essaie de décorer un ItemsControl de sorte que chaque élément aura un bouton Supprimer qui flotte sur le contenu de l'élément dans une condition spécifique inspirée par quelque peu par l'interface utilisateur de l'iPhone. J'ai quelques façons de voir comment je peux aborder cela, mais je pourrais utiliser les conseils d'autres personnes de WPF qui pourraient avoir une meilleure idée de la meilleure façon de procéder. Voici une image maquette pour aider à exprimer ce que j'essaie de faire.Comment créer une superposition pour chaque élément d'un ItemsControl?

Example mock-up

Mes pensées actuelles sont d'essayer de tenter cela en utilisant uniquement XAML uniquement à l'aide des styles, des modèles et des propriétés peut-être jointes si nécessaire. L'idée est de créer un DataTemplate conditionnel pour le contrôle des éléments qui encapsulerait le contenu original avec un adorateur contenant mon bouton Supprimer. Afin d'avoir un état sur mes ItemsControl pour savoir si je suis dans un mode de suppression ou non, je pense peut-être à créer une propriété attachée que je peux ensuite définir de différentes façons, comme la lier à l'état d'un bouton bascule ou d'une case à cocher par exemple. À ce stade, le concept est logique, mais les détails sont un peu flou à savoir si l'utilisation de ItemTemplate est le meilleur coup car dans certains cas un ItemTemplate peut déjà exister pour un ItemsControl donné et je ne veux pas l'écraser mais au lieu voudrait seulement l'envelopper (si cela a du sens). Je pense que si je tire sur off je devrais pouvoir appliquer ceci à n'importe quel contrôle d'articles en spécifiant le style et peut-être une propriété jointe.

Si quelqu'un pourrait aider à illustrer ces détails plus fins ou offrir de meilleures suggestions sur la façon dont je pourrais faire, s'il vous plaît partager.

Répondre

1

J'ai créé la maquette suivante pour illustrer un moyen simple de le faire, en utilisant un seul DataTemplate quelques liaisons. Vous êtes définitivement sur la bonne voie.

<Window x:Class="TestWpfApplication.Foods" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:local="clr-namespace:TestWpfApplication" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" 
Title="Foods" ResizeMode="NoResize" 
SizeToContent="WidthAndHeight" 
DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
<Window.Resources> 
    <local:BoolToVisConverter x:Key="BoolToVisConverter"/> 
</Window.Resources> 
<StackPanel Background="LightGray"> 
    <ToggleButton Name="EditModeToggle" Content="Edit" HorizontalAlignment="Right" FontFamily="Arial" Padding="4" 
        Background="#7FA4E6" Foreground="White" BorderBrush="Black" Width="60" Margin="5,5,5,0"/> 
    <ListBox ItemsSource="{Binding Items}" 
      Background="#999" BorderBrush="Black" Margin="5"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Border CornerRadius="8" Background="#3565BC" Padding="8" 
         BorderBrush="#333" BorderThickness="1" Margin="2" Width="255"> 
        <StackPanel Orientation="Horizontal"> 
         <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=RemoveItemCommand}" 
           Visibility="{Binding ElementName=EditModeToggle, Path=IsChecked, Converter={StaticResource BoolToVisConverter}}"> 
          <Button.Content> 
           <TextBlock Foreground="Red" Text="X" FontWeight="Bold"/> 
          </Button.Content> 
         </Button> 
         <TextBlock Text="{Binding}" Margin="12,0" Foreground="#AAA" VerticalAlignment="Center" 
            FontSize="14" FontWeight="Bold" FontFamily="Arial"/> 
        </StackPanel> 
       </Border> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</StackPanel> 

Vous n'avez pas besoin beaucoup de code pour faire ce travail, mais il y a encore un peu de code-behind, principalement pour le RoutedCommand:

public partial class Foods : Window 
{ 
    private ObservableCollection<String> items = new ObservableCollection<string>(); 
    private RoutedCommand removeItemCommand = new RoutedCommand(); 

    public Foods() 
    { 
     InitializeComponent(); 

     items.Add("Ice Cream"); 
     items.Add("Pizza"); 
     items.Add("Apple"); 

     CommandBindings.Add(new CommandBinding(removeItemCommand, ExecutedRemoveItem)); 
    } 

    public ObservableCollection<String> Items 
    { 
     get { return items; } 
    } 

    public RoutedCommand RemoveItemCommand 
    { 
     get { return removeItemCommand; } 
    } 

    private void ExecutedRemoveItem(object sender, ExecutedRoutedEventArgs e) 
    { 
     DependencyObject container = 
      ItemsControl.ContainerFromElement(e.Source as ItemsControl, e.OriginalSource as DependencyObject); 
     ListBoxItem item = container as ListBoxItem; 
     items.Remove(item.Content as String); 
    } 
} 

Et le résultat pourrait être fait beaucoup plus visuellement attrayant, évidemment, mais j'ai presque dupliqué votre idée haha:

alt text http://img697.imageshack.us/img697/7033/foodswindow.png

2

Normalement, vous ajouteriez quelque chose comme ceci dans un ItemContainerStyle afin de ne pas jouer avec le DataTemplate lui-même chaque fois que vous voulez l'appliquer. Bien que cela soit simple avec un ListBox dans lequel vous pouvez modifier le Template pour ListBoxItem, malheureusement, la base ItemsControl utilise simplement ContentPresenter comme conteneur et ne peut donc pas être modélisée de la même manière. Si vous voulez vraiment que cela soit réutilisable, je vous suggère de l'intégrer dans un nouveau ItemsControl personnalisé que vous pouvez remplacer pour remplacer un standard sans avoir à modifier le DataTemplate spécifique utilisé. Cela vous permettra également de conclure la propriété que vous auriez créé en externe en tant que prop attaché et la commande delete du contrôle lui-même.

Il est évident que la logique de suppression et le style visuel n'a pas été fait ici, mais cela devrait vous aider à démarrer:

public class DeleteItemsControl : ItemsControl 
{ 
    public static readonly DependencyProperty CanDeleteProperty = DependencyProperty.Register(
     "CanDelete", 
     typeof(bool), 
     typeof(DeleteItemsControl), 
     new UIPropertyMetadata(null)); 

    public bool CanDelete 
    { 
     get { return (bool)GetValue(CanDeleteProperty); } 
     set { SetValue(CanDeleteProperty, value); } 
    } 

    public static RoutedCommand DeleteCommand { get; private set; } 

    static DeleteItemsControl() 
    { 
     DeleteCommand = new RoutedCommand("DeleteCommand", typeof(DeleteItemsControl)); 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(DeleteItemsControl), new FrameworkPropertyMetadata(typeof(DeleteItemsControl))); 
    } 

    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new DeleteItem(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return item is DeleteItem; 
    } 
} 

public class DeleteItem : ContentControl 
{ 
    static DeleteItem() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(DeleteItem), new FrameworkPropertyMetadata(typeof(DeleteItem))); 
    } 

}

Cela irait dans generic.xaml ou vous pouvez simplement les appliquer comme normale styles dans votre application:

<Style TargetType="{x:Type local:DeleteItemsControl}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:DeleteItemsControl}"> 
       <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 
        <ItemsPresenter/> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

<Style TargetType="{x:Type local:DeleteItem}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="{x:Type local:DeleteItem}"> 
       <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"> 
        <DockPanel> 
         <Button Command="local:DeleteItemsControl.DeleteCommand" Content="X" HorizontalAlignment="Left" VerticalAlignment="Center" 
          Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:DeleteItemsControl}}, Path=CanDelete, Converter={StaticResource BooleanToVisibilityConverter}}"/> 
         <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/> 
        </DockPanel> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
Questions connexes