【问题标题】:How to create an overlay for each item in an ItemsControl?如何为 ItemsControl 中的每个项目创建叠加层?
【发布时间】:2010-01-21 19:17:47
【问题描述】:

我正在尝试装饰一个 ItemsControl,以便每个项目都有一个删除按钮,该按钮在受 iPhone UI 启发的特定条件下浮动在项目的内容上。我有几种方法可以解决这个问题,但我可以使用其他 WPF 人员的一些指导,他们可能对如何最好地做到这一点有更好的了解。下面是一个模拟图像,以帮助表达我正在尝试做的事情。

我目前的想法是尝试仅使用 XAML 来尝试此操作,仅使用样式、模板以及必要时可能附加的属性。这个想法是为项目控件创建条件 DataTemplate,它会以某种方式使用包含我的删除按钮的装饰器来包装原始内容。为了在我的 ItemsControl 上有一个状态以了解我是否处于 删除模式,我正在考虑创建一个附加属性,然后我可以通过多种方式设置该属性,例如例如,将其绑定到切换按钮或复选框的状态。

在这一点上,这个概念是有道理的,但我有点不清楚使用 ItemTemplate 是否是最好的举措,因为在某些情况下,给定 ItemsControl 的 ItemTemplate 可能已经存在,我不想覆盖它但是相反,只想包装它(如果有意义的话)。我在想,如果我成功了,我应该可以通过指定样式和附加属性来将其应用于任何项目控件。

如果有人可以帮助说明这些更详细的细节或提供更好的建议,请分享。

【问题讨论】:

    标签: wpf xaml overlay itemscontrol adorner


    【解决方案1】:

    通常,您会在 ItemContainerStyle 中添加类似的内容,以免每次要应用时都弄乱 DataTemplate 本身。虽然使用 ListBox 很简单,您可以在其中修改 ListBoxItem 的模板,但不幸的是,基本 ItemsControl 仅使用 ContentPresenter 作为其容器,因此不能以相同的方式进行模板化。

    如果您真的希望它可重复使用,我建议您将它包装到一个新的自定义 ItemsControl 中,您可以将其替换为标准的,而无需修改正在使用的特定 DataTemplate。这也将允许您将原本在外部创建的属性作为附加属性和控件本身中的删除命令包装起来。

    显然这里没有完成删除逻辑和视觉样式,但这应该可以帮助您开始:

    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)));
        }
    

    }

    这将放在 Generic.xaml 中,或者您可以像在您的应用中使用普通样式一样应用它们:

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

    【讨论】:

      【解决方案2】:

      我创建了以下模型来说明一种简单的方法可以做到这一点,使用单个DataTemplate 几个绑定。你肯定是在正确的轨道上。

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

      您不需要太多代码来完成这项工作,但仍有一些代码隐藏,主要用于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);
          }
      }
      

      显然,结果可以在视觉上更具吸引力,但我几乎复制了你的想法哈哈:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多