2010-03-24 28 views
53

Tôi cần hiển thị danh sách các số từ bộ sưu tập trong Điều khiển mục. Vì vậy, các mục là: "1", "2", "3".Làm cách nào để có thể thêm dấu phân tách giữa các mục trong một ItemsControl

Khi chúng được hiển thị, tôi cần chúng được phân tách bằng dấu phẩy (hoặc một cái gì đó tương tự). Vì vậy, 3 mục trên sẽ trông như thế này: "1, 2, 3".

Tôi làm cách nào để thêm dấu phân cách vào các mục riêng lẻ mà không bị tát vào cuối danh sách?

Tôi không bị mắc kẹt khi sử dụng ItemsControl, nhưng đó là những gì tôi đã bắt đầu sử dụng.

Trả lời

98
<ItemsControl ItemsSource="{Binding Numbers}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <!-- could use a WrapPanel if more appropriate for your scenario --> 
      <StackPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock x:Name="commaTextBlock" Text=", "/> 
       <TextBlock Text="{Binding .}"/> 
      </StackPanel> 
      <DataTemplate.Triggers> 
       <DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}"> 
        <Setter Property="Visibility" TargetName="commaTextBlock" Value="Collapsed"/> 
       </DataTrigger> 
      </DataTemplate.Triggers> 
     </DataTemplate> 

    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Tôi đến câu hỏi của bạn vì tôi đang tìm kiếm giải pháp trong Silverlight, không có nguồn dữ liệu tương đối trước đó.

+1

@foson: Tôi chưa bao giờ tìm thấy. Tôi đã kết thúc bằng cách sử dụng một lề âm để "cắt" dấu "," trong văn bản. Nó cảm thấy bẩn thỉu, nhưng nó hoạt động. –

+0

Bất kỳ giải pháp nào cho 'PreviousData' trong Silverlight? – Shimmy

+0

Điều gì về việc sử dụng chỉ mục của mục và so sánh với số không? – MikeKulls

1

Tôi đã tìm ra giải pháp mà tôi đã kết thúc.

Tôi đã kết thúc việc tập hợp các mục của mình vào Văn bản của một TextBlock và sử dụng bộ chuyển đổi giá trị để thay đổi tập hợp các mục bị ràng buộc thành chuỗi được định dạng.

3

Bạn cũng có thể multibind để ItemsControl.AlternationIndex và ItemsControl.Count và so sánh AlternationIndex để đếm để xem bạn có phải là mục cuối cùng không.

Đặt AlternationIndex đủ cao để chứa tất cả các mục của bạn sau đó tạo ra một LastItemConverter với một phương pháp Chuyển đổi tìm kiếm một cái gì đó như thế này:

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var alterationCount = (int)values[0]; 
     var itemCount = (int)values[1]; 
     if (itemCount > 1) 
     { 
      return alterationCount == (itemCount - 1) ? Visibility.Collapsed : Visibility.Visible; 
     } 

     return Visibility.Collapsed; 
    } 
+0

Người ta có thể đặt dải phân cách trước nội dung của một mục trong mẫu. Sau đó, nó đủ để liên kết với ** AlternationIndex ** chỉ và ẩn phân chia trong mục đầu tiên (AlternationIndex == 0). – baSSiLL

4

Đối với một giải pháp Silverlight tương thích tổng quát hơn, tôi lấy một điều khiển từ ItemsControl (SeperatedItemsControl). Mỗi mục được gói trong một SeperatedItemsControlItem, giống như ListBoxItem của ListBox. Mẫu cho SeperatedItemsControlItem chứa một seperator và một ContentPresenter. Người seperator cho phần tử đầu tiên trong bộ sưu tập bị ẩn. Bạn có thể dễ dàng sửa đổi giải pháp này để tạo ra một seperator thanh ngang giữa các mục, đó là những gì tôi tạo ra nó.

MainWindow.xaml:

<Window x:Class="ItemsControlWithSeperator.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:ItemsControlWithSeperator" 
mc:Ignorable="d" 
d:DesignHeight="300" d:DesignWidth="400"> 
<UserControl.Resources> 
    <local:ViewModel x:Key="vm" /> 

</UserControl.Resources> 
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource vm}"> 

    <local:SeperatedItemsControl ItemsSource="{Binding Data}"> 
     <local:SeperatedItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Orientation="Horizontal" /> 
      </ItemsPanelTemplate> 
     </local:SeperatedItemsControl.ItemsPanel> 
     <local:SeperatedItemsControl.ItemContainerStyle> 
      <Style TargetType="local:SeperatedItemsControlItem"> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="local:SeperatedItemsControlItem" > 
          <StackPanel Orientation="Horizontal"> 
           <TextBlock x:Name="seperator">,</TextBlock> 
           <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}"/> 
          </StackPanel> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 
     </local:SeperatedItemsControl.ItemContainerStyle> 
    </local:SeperatedItemsControl> 
</Grid> 

C# Code:

using System; 
using System.Windows; 
using System.Windows.Controls; 

namespace ItemsControlWithSeperator 
{ 

    public class ViewModel 
    { 
     public string[] Data { get { return new[] { "Amy", "Bob", "Charlie" }; } } 
    } 

    public class SeperatedItemsControl : ItemsControl 
    { 

     public Style ItemContainerStyle 
     { 
      get { return (Style)base.GetValue(SeperatedItemsControl.ItemContainerStyleProperty); } 
      set { base.SetValue(SeperatedItemsControl.ItemContainerStyleProperty, value); } 
     } 

     public static readonly DependencyProperty ItemContainerStyleProperty = 
      DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(SeperatedItemsControl), null); 

     protected override DependencyObject GetContainerForItemOverride() 
     { 
      return new SeperatedItemsControlItem(); 
     } 
     protected override bool IsItemItsOwnContainerOverride(object item) 
     { 
      return item is SeperatedItemsControlItem; 
     } 
     protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
     { 
      //begin code copied from ListBox class 

      if (object.ReferenceEquals(element, item)) 
      { 
       return; 
      } 

      ContentPresenter contentPresenter = element as ContentPresenter; 
      ContentControl contentControl = null; 
      if (contentPresenter == null) 
      { 
       contentControl = (element as ContentControl); 
       if (contentControl == null) 
       { 
        return; 
       } 
      } 
      DataTemplate contentTemplate = null; 
      if (this.ItemTemplate != null && this.DisplayMemberPath != null) 
      { 
       throw new InvalidOperationException(); 
      } 
      if (!(item is UIElement)) 
      { 
       if (this.ItemTemplate != null) 
       { 
        contentTemplate = this.ItemTemplate; 
       } 

      } 
      if (contentPresenter != null) 
      { 
       contentPresenter.Content = item; 
       contentPresenter.ContentTemplate = contentTemplate; 
      } 
      else 
      { 
       contentControl.Content = item; 
       contentControl.ContentTemplate = contentTemplate; 
      } 

      if (ItemContainerStyle != null && contentControl.Style == null) 
      { 
       contentControl.Style = ItemContainerStyle; 
      } 

      //end code copied from ListBox class 

      if (this.Items.Count > 0) 
      { 
       if (object.ReferenceEquals(this.Items[0], item)) 
       { 
        var container = element as SeperatedItemsControlItem; 
        container.IsFirstItem = true; 
       } 
      } 
     } 
     protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
     { 
      base.OnItemsChanged(e); 
      if (Items.Count > 1) 
      { 
       var container = (ItemContainerGenerator.ContainerFromIndex(1) as SeperatedItemsControlItem); 
       if (container != null) container.IsFirstItem = false; 
      } 
      if (Items.Count > 0) 
      { 
       var container = (ItemContainerGenerator.ContainerFromIndex(0) as SeperatedItemsControlItem); 
       if (container != null) container.IsFirstItem = true; 
      } 
     } 

    } 

    public class SeperatedItemsControlItem : ContentControl 
    { 
     private bool isFirstItem; 
     public bool IsFirstItem 
     { 
      get { return isFirstItem; } 
      set 
      { 
       if (isFirstItem != value) 
       { 
        isFirstItem = value; 
        var seperator = this.GetTemplateChild("seperator") as FrameworkElement; 
        if (seperator != null) 
        { 
         seperator.Visibility = isFirstItem ? Visibility.Collapsed : Visibility.Visible; 
        } 
       } 
      } 
     }  
     public override void OnApplyTemplate() 
     { 
      base.OnApplyTemplate(); 

      if (IsFirstItem) 
      { 
       var seperator = this.GetTemplateChild("seperator") as FrameworkElement; 
       if (seperator != null) 
       { 
        seperator.Visibility = Visibility.Collapsed; 
       } 
      } 
     } 
    } 
} 
14

The current accepted answer đã cho tôi một XAML ràng buộc lỗi cho mỗi mẫu, mà tôi lo ngại có thể ảnh hưởng đến hiệu suất. Thay vào đó, tôi đã làm như dưới đây, sử dụng AlternationIndex để ẩn dấu tách đầu tiên. (Lấy cảm hứng từ this answer.)

<ItemsControl ItemsSource="{Binding Numbers}" AlternationCount="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <StackPanel Orientation="Horizontal"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock x:Name="SeparatorTextBlock" Text=", "/> 
       <TextBlock Text="{Binding .}"/> 
      </StackPanel> 
     <DataTemplate.Triggers> 
      <Trigger Property="ItemsControl.AlternationIndex" Value="0"> 
       <Setter Property="Visibility" TargetName="SeparatorTextBlock" Value="Collapsed" /> 
      </Trigger> 
     </DataTemplate.Triggers> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
+1

Vui nhộn. Tôi đã trở lại đây sau khi có vấn đề với dấu phẩy của tôi gắn bó xung quanh sau khi danh sách đếm thay đổi bằng cách sử dụng câu trả lời được chấp nhận. Giải pháp của bạn đã giải quyết được vấn đề của tôi, cảm ơn bạn! –

+1

Tuyệt vời - cảm ơn @Carter !! – Chris

+0

Đối với tôi hoạt động không có dấu chấm trên dòng này thay vì luka

Các vấn đề liên quan