2010-08-22 14 views
19

Phần sau đây tương tự như những gì tôi đang cố gắng hoàn thành. Tuy nhiên, tôi gặp lỗiChỉ định ControlTemplate cho ItemsControl.ItemContainerStyle

Giá trị thuộc tính không hợp lệ.

trên Mẫu Setter. Tôi nghi ngờ đó là vì tôi đã không chỉ định một TargetType cho Style; tuy nhiên, tôi không biết loại vùng chứa cho ItemsControl.

<ItemsControl> 
    <ItemsControl.ItemContainerStyle> 
     <Style> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate> 
         <StackPanel> 
          <TextBlock Text="Some Content Here" /> 
          <ContentPresenter /> 
          <Button Content="Edit" /> 
         </StackPanel> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
    <!-- heterogenous controls --> 
    <ItemsControl.Items> 
     <Button Content="Content 1" /> 
     <TextBox Text="Content 2" /> 
     <Label Content="Content 3" /> 
    </ItemsControl.Items> 
</ItemsControl> 

Trả lời

35

Bạn có thể đủ điều kiện tên thuộc tính với tên loại:

<Setter Property="Control.Template"> 

Các container cho ItemsControl là bình thường một ContentPresenter, nhưng nếu đứa trẻ là một UIElement sau đó nó sẽ không sử dụng một thùng đựng hàng. Trong trường hợp này, tất cả các con đều là các điều khiển, do đó ItemContainerStyle sẽ áp dụng trực tiếp cho chúng. Nếu bạn đã thêm một mục không phải là UIElement, bộ setter đó sẽ đặt thuộc tính Control.Template trên ContentPresenter, thành công nhưng không có hiệu lực.

Thực ra, nó giống như những gì bạn muốn là quấn mỗi đứa trẻ vào một thùng chứa, ngay cả khi chúng đã là một UIElement. Để làm điều đó, bạn sẽ phải sử dụng một lớp con của ItemsControl. Bạn có thể sử dụng cái hiện có như ListBox, hoặc bạn có thể phân lớp ItemsControl và ghi đè GetContainerForItemOverrideIsItemItsOwnContainerOverride để gói các vật phẩm trong vùng chứa của riêng bạn. Bạn có thể bọc chúng trong một ContentControl và sau đó sử dụng nó như TargetType cho Style.

public class CustomItemsControl 
    : ItemsControl 
{ 
    protected override DependencyObject GetContainerForItemOverride() 
    { 
     return new ContentControl(); 
    } 

    protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     // Even wrap other ContentControls 
     return false; 
    } 
} 

Bạn cũng sẽ cần phải đặt TargetType trên ControlTemplate sao cho ContentPresenter sẽ liên kết với thuộc tính Content:

<ControlTemplate TargetType="ContentControl"> 
+0

Hoạt động bơi lội! Tôi đã cố gắng làm tất cả những điều đó với XAML, và chỉ một vài dòng mã để lấy được một lớp làm cho mọi thứ trở nên vui vẻ, gọn gàng và sạch sẽ. –

+1

"Nếu bạn đã thêm một mục không phải là UIElement, setter đó sẽ đặt thuộc tính Control.Template trên ContentPresenter, thành công nhưng không có hiệu lực." - Tôi đã tìm kiếm các lứa tuổi trước khi tôi tìm thấy mẹo này! – Daniel

2

Ngoài ra nếu bạn chỉ muốn làm tất cả của nó với XAML bạn có thể chỉ cần sử dụng ListBox thay vì ItemsControl và xác định kiểu cho ListBoxItem:

 <ListBox ItemsSource="{Binding Elements.ListViewModels}"> 
     <ListBox.Resources> 
      <Style TargetType="ListBoxItem"> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="ListBoxItem"> 
          <StackPanel> 
           <TextBlock>Some Content Here</TextBlock> 
           <ContentPresenter Content="{TemplateBinding Content}" /> 
           <Button>Edit</Button> 
          </StackPanel> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 
     </ListBox.Resources> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel /> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 

Lưu ý rằng vì tôi đang sử dụng ListBox vùng chứa là ListBoxItem (Thường là thùng chứa cho WP Điều khiển danh sách mặc định của F luôn được đặt tên là Mục) để chúng tôi tạo kiểu cho ListBoxItem:

<Style TargetType="ListBoxItem"> 

Sau đó, chúng tôi tạo một ControlTemplate mới cho ListBoxItem. Xin lưu ý rằng ContentPresenter không được sử dụng vì nó luôn xuất hiện trong các bài viết và hướng dẫn, bạn cần phải liên kết mẫu với thuộc tính Nội dung của ListBoxItem, vì vậy nó sẽ hiển thị nội dung cho mục đó.

<ContentPresenter Content="{TemplateBinding Content}" /> 

Tôi vừa gặp vấn đề tương tự và sửa nó theo cách này. Tôi không muốn một số chức năng của ListBox (lựa chọn mục) và bằng cách sử dụng kỹ thuật này việc lựa chọn mục không hoạt động nữa.