WrapPanel拉伸边距,如Windows文件浏览器

时间:2016-08-13 11:15:16

标签: c# wpf windows user-interface wrappanel

我想重新记录Windows中带有图标视图的文件夹的行为。当我们水平调整大小时,直到新图标适合当前行,边距会增加,以便当前行中的所有图标按比例填充整个宽度。

我的整个XAML代码如下。目前我的应用程序的行为就像你在这两张图片中看到的那样:

Before resizing, you can see free space on the right enter image description here

如何拉伸元素之间的边距,以便始终填充整行?

<Window x:Class="drag_out_test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:drag_out_test"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <UniformGrid>
        <ListBox Name="FileListBox" 
                 MouseMove="FileView_MouseMove" 
                 MouseDown="FileListBox_MouseDown"
                 ScrollViewer.HorizontalScrollBarVisibility="Disabled"                 
                 Padding="10">

            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel
                        MaxWidth="{Binding ActualWidth,ElementName=FileListBox}">

                    </WrapPanel>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

            <ListBox.ItemContainerStyle>

                <Style TargetType="ListBoxItem">
                    <Setter Property="Margin"
                        Value="5,0,5,0" />
                    <Setter Property="Padding"
                            Value="5,0,5,0"/>
                </Style>
            </ListBox.ItemContainerStyle>

            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Rectangle Width="50" Height="50" Fill="Black">

                    </Rectangle>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </UniformGrid>
</Window>

2 个答案:

答案 0 :(得分:0)

这是自定义控件的最简单示例。只有水平方向和探险家视图。

public class StretchyWrapPanel : Panel
    {
        // Default vertical offset
        const int ElementVerticalOffset = 5;

        protected override Size MeasureOverride(Size constraint)
        {
            Size currentLineSize = new Size();
            Size panelSize = new Size();

            foreach (UIElement element in InternalChildren)
            {
                // Compute element size
                element.Measure(constraint);
                Size desiredSize = element.DesiredSize;

                // Go to new line
                if (currentLineSize.Width + desiredSize.Width > constraint.Width)
                {
                    panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                    panelSize.Height += currentLineSize.Height + ElementVerticalOffset;
                    currentLineSize = desiredSize;

                    // If width of element is more than our constrait -> go to new line
                    if (desiredSize.Width > constraint.Width)
                    {
                        panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                        panelSize.Height += currentLineSize.Height + ElementVerticalOffset;
                        currentLineSize = new Size();
                    }
                }
                // If element can be placed in line
                else
                {
                    currentLineSize.Width += desiredSize.Width;
                    currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
                }
            }
            panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
            panelSize.Height += currentLineSize.Height;
            return panelSize;
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            var currentLineSize = new Size();
            Size panelSize = new Size();

            double offsetLeft = 0;
            double offsetTop = 0;

            foreach (UIElement element in InternalChildren)
            {
                Size desiredSize = element.DesiredSize;

                var elementCountInLine = (int)(finalSize.Width / desiredSize.Width);
                int elementHorizontalOffset = (int)((finalSize.Width - elementCountInLine * desiredSize.Width) / (elementCountInLine));

                if (currentLineSize.Width + desiredSize.Width + elementHorizontalOffset > finalSize.Width)
                {
                    panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                    panelSize.Height += currentLineSize.Height;
                    currentLineSize = desiredSize;

                    if (desiredSize.Width > finalSize.Width)
                    {
                        panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                        panelSize.Height += currentLineSize.Height;
                        currentLineSize = new Size();
                    }
                    offsetLeft = 0;
                    offsetTop += desiredSize.Height + ElementVerticalOffset;
                }
                else
                {
                    currentLineSize.Width += desiredSize.Width + elementHorizontalOffset;
                    currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
                }
                element.Arrange(new Rect(new Point(offsetLeft, offsetTop), element.DesiredSize));
                offsetLeft += desiredSize.Width + elementHorizontalOffset;
            }

            return finalSize;
        }
    }

答案 1 :(得分:0)

我修改了您的答案Pavel,然后得到了我需要的行为:

public class CustomWrapPanel : Panel
{
    // Default vertical offset
    const int ElementVerticalOffset = 5;

    protected override Size MeasureOverride(Size constraint)
    {
        Size currentLineSize = new Size();
        Size panelSize = new Size();

        foreach (UIElement element in InternalChildren)
        {
            // Compute element size
            element.Measure(constraint);
            Size desiredSize = element.DesiredSize;

            // Go to new line
            if (currentLineSize.Width + desiredSize.Width > constraint.Width)
            {
                panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                panelSize.Height += currentLineSize.Height + ElementVerticalOffset;
                currentLineSize = desiredSize;

                // If width of element is more than our constrait -> go to new line
                if (desiredSize.Width > constraint.Width)
                {
                    panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                    panelSize.Height += currentLineSize.Height + ElementVerticalOffset;
                    currentLineSize = new Size();
                }
            }
            // If element can be placed in line
            else
            {
                currentLineSize.Width += desiredSize.Width;
                currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
            }
        }
        panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
        panelSize.Height += currentLineSize.Height;
        return panelSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        var currentLineSize = new Size();
        Size panelSize = new Size();

        double offsetLeft = 0;
        double offsetTop = 0;

        foreach (UIElement element in InternalChildren)
        {
            Size desiredSize = element.DesiredSize;

            var elementCountInLine = (int)(finalSize.Width / desiredSize.Width);
            int elementHorizontalOffset = (int)((finalSize.Width - elementCountInLine * desiredSize.Width) / (elementCountInLine + 1));

            if (offsetLeft == 0) { offsetLeft = elementHorizontalOffset; }

            if (currentLineSize.Width + desiredSize.Width + elementHorizontalOffset > finalSize.Width)
            {
                panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                panelSize.Height += currentLineSize.Height;
                currentLineSize = desiredSize;

                if (desiredSize.Width > finalSize.Width)
                {
                    panelSize.Width = Math.Max(currentLineSize.Width, panelSize.Width);
                    panelSize.Height += currentLineSize.Height;
                    currentLineSize = new Size();
                }
                offsetLeft = elementHorizontalOffset;
                offsetTop += desiredSize.Height + ElementVerticalOffset;
            }
            else
            {
                currentLineSize.Width += desiredSize.Width + elementHorizontalOffset;
                currentLineSize.Height = Math.Max(desiredSize.Height, currentLineSize.Height);
            }
            element.Arrange(new Rect(new Point(offsetLeft, offsetTop), element.DesiredSize));
            offsetLeft += desiredSize.Width + elementHorizontalOffset;
        }

        return finalSize;
    }
}