使ListBox大小适合用作其ItemsPresenter的ItemsPanel

时间:2013-02-08 15:07:46

标签: c# wpf xaml custom-controls generic.xaml

我有一个自定义控件ListBox,我想根据其ItemsPanel的大小调整其大小。对于items面板,我有一个自定义控件WrapPanel,可以相应地排列项目。正如您在屏幕截图中看到的那样,ListBox更喜欢将自身大小调整为其父控件或availableSize。

然后我尝试创建一个自定义控件Grid,它有一个ItemsSource属性,将项目传递给它的列表框。但这也不起作用。当网格排列时,ListBox会排列,这将导致网格排列等等。

所以我的问题是,如何创建一个具有ItemsSource属性的自定义控件和一个根据子元素的内容调整自身大小的ItemsPresenter?

Screenshot of ListBox Custom Control

2 个答案:

答案 0 :(得分:1)

您只需将ListBox Horizo​​ntalAlignment设置为Left,将VerticalAlignment设置为Top。这应该可以解决问题。

简单示例:

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

编辑:它也适用于绑定方案:

<强> 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 { }
}

答案 1 :(得分: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>