2013-02-08 5 views
2

У меня есть собственный элемент управления ListBox, который я бы хотел настроить в соответствии с размером его ItemsPanel. Для панели элементов у меня есть настраиваемый элемент управления WrapPanel, который соответствующим образом упорядочивает элементы. Как вы можете видеть на снимке экрана, ListBox предпочитает определять размер своего родительского элемента управления или доступного размера.Сделать размер ListBox подходящим для ItemsPanel, используемого как его ItemsPresenter

Итак, я попытался создать настраиваемую сетку управления, у которой было свойство ItemsSource, которое передало элементы в свой список. Но это тоже не сработало. Когда Grid будет устраивать, ListBox будет организовывать, что приведет к упорядочению сетки и так далее.

Итак, мой вопрос: как создать пользовательский элемент управления, обладающий свойством ItemsSource и ItemsPresenter, который сам по размеру соответствует своим детям?

Screenshot of ListBox Custom Control

ответ

1

Это то, что я должен был сделать, чтобы получить функциональность я хотел. Сначала я должен создать свой SquareWrapPanel. Здесь происходит волшебство и упорядочивает мои предметы так, как я хочу.

protected override Size ArrangeOverride(Size finalSize) 
    { 
     return ArrangeByChildCount(finalSize); 
    } 

    private Size ArrangeByChildCount(Size finalSize) 
    { 

     double childWidth = 0; 
     double childHeight = 0; 


     foreach (UIElement e in Children) 
     { 
      e.Measure(finalSize); 

      childWidth = e.DesiredSize.Width; 
      childHeight = e.DesiredSize.Height; 
     } 

     if (Children.Count > 0) 
     { 
      int square = (int)Math.Sqrt(Children.Count); 


      int rowCount = square + Children.Count % square; 
      int columnCount = square; 

      double height = rowCount * childHeight; 
      double width = columnCount * childWidth; 

      Size size = new Size(width, height); 
      base.ArrangeOverride(size); 
      return size; 
     } 
     else 
     { 
      return new Size(300, 300); 
     } 
    } 

Затем я создал пользовательскую панель, которая расширила ItemsControl. Таким образом, я мог бы привязать к нему коллекцию предметов. В коде нет ничего, но вот стиль, который мне пришлось использовать.

<Style TargetType="{x:Type local:SquareItemsPanel}" BasedOn="{StaticResource {x:Type ItemsControl}}"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="ItemsControl"> 
       <Border BorderBrush="Black" BorderThickness="2" CornerRadius="4"> 
        <Expander x:Name="exp" Header="View"> 
         <local:SquareWrapPanel IsItemsHost="True"/> 
        </Expander> 
       </Border> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 
1

Вы просто должны установить ListBox HorizontalAlignment налево, и VerticalAlignment наверх. Это должно сделать трюк.

Простой пример:

MainWindow.xaml

<Window x:Class="ListBoxFitItemsPanel.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="400" Width="400"> 
    <ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" Background="Red" HorizontalAlignment="Left" VerticalAlignment="Top" > 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel Background="AntiqueWhite" Margin="5" /> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 

     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
    </ListBox> 
</Window> 

enter image description here

EDIT: Он также работает в Binding сценария:

MainWindow.xaml

<Window x:Class="ListBoxFitItemsPanel.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:ListBoxFitItemsPanel" 
     Title="MainWindow" Height="400" Width="400"> 
    <Window.Resources> 
     <DataTemplate DataType="{x:Type local:Item}"> 
      <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" /> 
     </DataTemplate> 
    </Window.Resources> 
    <ListBox ItemsSource="{Binding Items}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" Background="Red" HorizontalAlignment="Left" VerticalAlignment="Top" > 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel Background="AntiqueWhite" Margin="5" /> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 
</Window> 

MainWindow.xaml.cs

using System.Collections.Generic; 
using System.Windows; 

namespace ListBoxFitItemsPanel 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = this; 
     } 

     public IEnumerable<Item> Items 
     { 
      get 
      { 
       for (int i = 0; i < 9; i++) 
       { 
        yield return new Item(); 
       } 
      } 
     } 
    } 

    public class Item { } 
} 
+0

Это не выход. Видите ли, ListBox по-прежнему укладывается в окно. Затем WrapPanel устраивает своих детей. Я хочу, чтобы ListBox хорошо вписывался в свою собственную ItemsPanel, которая уже определила ее размер. –

+0

+1 Это правильный ответ. «ListBox» заполняет панель контейнера. Вы должны выровнять его внутри своего родителя, используя 'HorizontalAlignment' и' VerticalAlignment' –

+0

@Jesse: В этом случае это не так. Пропуск двойной макеты измеряет и упорядочивает верхний контейнер на основе размера, возвращаемого всеми дочерними элементами. На скриншоте, который я опубликовал, Window backgroudn является белым, тогда как Backbox в Listbox является красным. Я установил разницу, чтобы сделать ее видимой. Вы можете видеть, что ListBox занял только пространство, необходимое для панели обертки. Если вы попытались установить высоту или ширину оберточной панели, ListBox не будет принимать больше. – Sisyphe

Смежные вопросы