【问题标题】:Make ListBox size to fit the ItemsPanel used as its ItemsPresenter使 ListBox 大小适合用作其 ItemsPresenter 的 ItemsPanel
【发布时间】:2013-02-08 15:07:45
【问题描述】:

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

然后我尝试制作一个自定义控件 Grid,它有一个 ItemsSource 属性,可以将项目传递给它的列表框。但这也没有用。当 Grid 进行排列时,ListBox 将 Arrange,这将导致 Grid 进行排列等等。

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

【问题讨论】:

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


    【解决方案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>
    

    编辑:它也适用于绑定场景:

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

    【讨论】:

    • 那不是退出它。你看,ListBox 仍然安排在窗口内。然后 WrapPanel 安排它的孩子。我想要的是 ListBox 很好地适应它自己的 ItemsPanel,它已经确定了它的大小。
    • +1 这是正确答案。 ListBox 正在填充它的容器面板。您需要使用 HorizontalAlignmentVerticalAlignment 将其与父级对齐
    • @Jesse :在这种情况下,它不会。双布局通道根据所有子级返回的大小测量和排列顶部容器。在我发布的屏幕截图中,Window 背景是白色的,而 Listbox 背景是红色的。我设置了一个边距以使其可见。您可以看到 ListBox 只占用了换行面板所需的空间。如果您尝试修复环绕面板的高度或宽度,ListBox 将不会占用更多。
    • 你们完全正确。但我有一个自定义包装面板作为 ItemsPanel,它说我要按 800 x 600 大小。它不会根据可用尺寸自行排列。它只关心它的子组件。那么,一旦调整了换行面板的大小,如何设置 ListBox 的大小?
    • 我想我明白了。我的自定义 WrapPanel 上的 MeasureOverride 无法正常工作。确定问题后,我会发布更新。
    【解决方案2】:

    这是我必须做的才能获得我想要的功能。首先我必须创建我的 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>
    

    【讨论】:

      猜你喜欢
      • 2011-04-13
      • 2019-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 2014-05-07
      • 1970-01-01
      相关资源
      最近更新 更多