2011-10-20 29 views
8

Tôi cần phải tạo kiểu cho các mục đầu tiên và cuối cùng của chế độ xem danh sách khác nhau. Để đạt được điều đó, tôi bắt đầu làm việc trên một giải pháp dựa trên câu trả lời đó: Use different template for last item in a WPF itemscontrolMẫu mục riêng biệt cho mục đầu tiên và cuối cùng trong một ListView

Về cơ bản, tôi có một tùy chỉnh ItemsTemplateSelector quyết định áp dụng mẫu dựa trên chỉ mục của mục trong các mục xem danh sách (mã bên dưới).

Nó hoạt động đúng cách ngoại trừ khi danh sách được cập nhật (một mục được thêm hoặc loại bỏ), các mẫu không được chọn lại (ví dụ, ban đầu, SingleItemTemplate được chọn vì có một mục duy nhất. một mục vào danh sách, mẫu của mục đầu tiên không được chuyển sang FirstItemTemplate). Làm cách nào để buộc chọn mẫu cho tất cả các mục?

public class FirstLastTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate DefaultTemplate { get; set; } 
    public DataTemplate FirstItemTemplate { get; set; } 
    public DataTemplate LastItemTemplate { get; set; } 
    public DataTemplate SingleItemTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     ListView lv = VisualTreeHelperEx.FindParentOfType<ListView>(container); 
     if (lv != null) 
     { 
      if (lv.Items.Count == 1) 
      { 
       return SingleItemTemplate; 
      } 

      int i = lv.Items.IndexOf(item); 
      if (i == 0) 
      { 
       return FirstItemTemplate; 
      } 
      else if (i == lv.Items.Count - 1) 
      { 
       return LastItemTemplate; 
      } 
     } 
     return DefaultTemplate; 
    } 
} 

Trả lời

14

Là một cách tiếp cận khác, tôi sẽ đề nghị liên kết các AlternationCount của ItemsControl đến số lượng các mục trong bộ sưu tập của bạn (ví dụ như các Count tài sản) của bạn. Sau đó, điều này sẽ chỉ định cho từng vùng chứa trong số ItemsControlAlternationIndex duy nhất của bạn (0, 1, 2, ... Đếm-1). Xem ở đây để biết thêm thông tin:

http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount.aspx

Khi mỗi container có một độc đáo AlternationIndex bạn có thể sử dụng một DataTrigger trong container của bạn Style để thiết lập ItemTemplate dựa tắt của chỉ số. Điều này có thể được thực hiện bằng cách sử dụng MultiBinding với công cụ chuyển đổi trả về True nếu chỉ mục bằng số, False nếu không. Tất nhiên bạn cũng có thể xây dựng một bộ chọn xung quanh phương pháp này. Ngoại trừ bộ chuyển đổi, cách tiếp cận này là tốt đẹp vì nó là một giải pháp duy nhất XAML.

Một ví dụ sử dụng một ListBox:

<Window x:Class="WpfApplication4.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib" 
     xmlns:System="clr-namespace:System;assembly=mscorlib" 
     xmlns:l="clr-namespace:WpfApplication4" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.Resources> 
      <Collections:ArrayList x:Key="MyCollection"> 
       <System:String>Item One</System:String> 
       <System:String>Item Two</System:String> 
       <System:String>Item Three</System:String> 
      </Collections:ArrayList> 

      <l:MyAlternationEqualityConverter x:Key="MyAlternationEqualityConverter" /> 

      <Style x:Key="MyListBoxItemStyle" TargetType="{x:Type ListBoxItem}"> 
       <Style.Triggers> 
        <DataTrigger Value="True"> 
         <DataTrigger.Binding> 
          <MultiBinding Converter="{StaticResource MyAlternationEqualityConverter}"> 
           <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListBox}}" Path="Items.Count" /> 
           <Binding RelativeSource="{RelativeSource Self}" Path="(ItemsControl.AlternationIndex)" /> 
          </MultiBinding> 
         </DataTrigger.Binding> 
         <!-- Could set the ItemTemplate instead --> 
         <Setter Property="Background" Value="Red"/> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </Grid.Resources> 

     <ListBox ItemsSource="{Binding Source={StaticResource MyCollection}}" 
       AlternationCount="{Binding RelativeSource={RelativeSource Self}, Path=Items.Count}" 
       ItemContainerStyle="{StaticResource MyListBoxItemStyle}" /> 
    </Grid> 

Trường hợp chuyển đổi có thể giống như thế:

class MyAlternationEqualityConverter : IMultiValueConverter 
{ 
    #region Implementation of IMultiValueConverter 

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values != null && values.Length == 2 && 
      values[0] is int && values[1] is int) 
     { 
      return Equals((int) values[0], (int) values[1] + 1); 
     } 

     return DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 

    #endregion 
} 
+0

Tôi tự hỏi tại sao bạn chưa so sánh bằng Ràng buộc của DataTrigger để ItemsCount và Giá trị cho AlternationCount? Có phải vì ItemCount không phải là một thuộc tính phụ thuộc và nó sẽ ném lỗi? Hoặc có lý do nào khác không? Bởi vì tôi thấy nó sẽ là một boolean bằng so sánh và tại sao chúng ta cần một công cụ chuyển đổi – CarbineCoder

+0

@ ramb00 Tôi đã thử và nhận: "A 'Binding" không thể được đặt trên thuộc tính' Giá trị 'của loại' DataTrigger '" . Có vẻ như Value không phải là một dependencyProp. –

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