自定义面板中的项目未正确排列

本文关键字:排列 项目 自定义 | 更新日期: 2023-09-27 17:56:40

您好,我需要一个具有多列和可变高度行的视图。我已经编写了一个自定义的 WrapPanel,如果显式给出它的子项,它就可以正常工作。当我在数据模板中提供带有用户控件的 ItemsControl 作为 WrapPanel 的子项时,会出现此问题。

我的自定义包装面板:

public class NewsFeedPanel : WrapPanel
{
    private int _NumberOfColumn = 0;
    private double _MaxColumnHeight = 0;
    private double _MinColumnHeight = 0;
    public double DefaultWidth
    {
        get { return (double)GetValue(DefaultWidthProperty); }
        set { SetValue(DefaultWidthProperty, value); }
    }
    public double HGap
    {
        get { return (double)GetValue(HGapProperty); }
        set { SetValue(HGapProperty, value); }
    }
    public double VGap
    {
        get { return (double)GetValue(VGapProperty); }
        set { SetValue(VGapProperty, value); }
    }

    // Using a DependencyProperty as the backing store for DefaultWidth.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DefaultWidthProperty =
        DependencyProperty.Register("DefaultWidth", typeof(double), typeof(NewsFeedPanel), new UIPropertyMetadata(0.0, (s, e) => { }));
    public static readonly DependencyProperty HGapProperty =
        DependencyProperty.Register("HGap", typeof(double), typeof(NewsFeedPanel), new UIPropertyMetadata(0.0, (s, e) => { }));
    public static readonly DependencyProperty VGapProperty =
        DependencyProperty.Register("VGap", typeof(double), typeof(NewsFeedPanel), new UIPropertyMetadata(0.0, (s, e) => { }));
    protected override Size MeasureOverride(Size constraint)
    {
        double _Width = constraint.Width;
        _Width = _Width - Margin.Left - Margin.Right;
        _Width = Math.Max(_Width, DefaultWidth + HGap + VGap);
        _NumberOfColumn = (int)(_Width - HGap) / (int)(DefaultWidth + HGap);
        double[] _ColumnHeightArray = new double[_NumberOfColumn > 0 ? _NumberOfColumn : 1];
        UIElementCollection children = InternalChildren;
        int count = children.Count;
        for (int i = 0; i < count; i++)
        {
            UIElement child = children[i];
            if (child == null) continue;
            int idx = getMinColumnIndex(_ColumnHeightArray);
            _MinColumnHeight = _ColumnHeightArray[idx];
            Size childConstraint = new Size(0, 0);
            childConstraint.Width = Math.Max(0.0, DefaultWidth);
            childConstraint.Height = Math.Max(0.0, constraint.Height - _MinColumnHeight);
            child.Measure(childConstraint);
            _ColumnHeightArray[idx] = _MinColumnHeight + VGap + child.DesiredSize.Height;
        }
        int maxIdx = getMaxColumnIndex(_ColumnHeightArray);
        int minIdx = getMinColumnIndex(_ColumnHeightArray);
        _MaxColumnHeight = _ColumnHeightArray[maxIdx] + VGap + Margin.Top + Margin.Bottom;
        _MinColumnHeight = _ColumnHeightArray[minIdx] + VGap + Margin.Top + Margin.Bottom;
        constraint.Height = _MaxColumnHeight;
        return (new Size(constraint.Width, _MaxColumnHeight));
    }

    protected override Size ArrangeOverride(Size totalAvailableSize)
    {
        double _Width = totalAvailableSize.Width;
        _Width = _Width - Margin.Left - Margin.Right;
        _NumberOfColumn = (int)(_Width - HGap) / (int)(DefaultWidth + HGap);
        double[] _ColumnHeightArray = new double[_NumberOfColumn > 0 ? _NumberOfColumn : 1];
        double _TotalHgap = HGap * (_ColumnHeightArray.Length + 1);
        double _TotalComponentWidth = DefaultWidth * _ColumnHeightArray.Length;
        double _TotalWidth = _TotalHgap + _TotalComponentWidth;
        double _EmptySpace = (_Width - _TotalWidth) / 2;

        //lock (InternalChildren)
        //{
        UIElementCollection children = InternalChildren;
        int count = children.Count;
        for (int i = 0; i < count; i++)
        {
            UIElement child = children[i];
            Rect finalRect = new Rect(0.0, 0.0, 0.0, 0.0);
            int idx = getMinColumnIndex(_ColumnHeightArray);
            _MinColumnHeight = _ColumnHeightArray[idx];
            _ColumnHeightArray[idx] = _MinColumnHeight + VGap + child.DesiredSize.Height;
            finalRect.X = Margin.Left + _EmptySpace + (idx * (DefaultWidth + HGap)) + HGap;
            finalRect.Y = _MinColumnHeight + VGap;
            finalRect.Width = child.DesiredSize.Width;
            finalRect.Height = child.DesiredSize.Height;
            child.Arrange(finalRect);
        }
        //}
        return totalAvailableSize;
    }
    private int getMinColumnIndex(double[] columnHeight)
    {
        int minIndex = 0;
        double minHeight = columnHeight[0];
        int idx = 1;
        while (idx < columnHeight.Length)
        {
            if (columnHeight[idx] < minHeight)
            {
                minHeight = columnHeight[idx];
                minIndex = idx;
            }
            idx++;
        }
        return minIndex;
    }
    private int getMaxColumnIndex(double[] columnHeight)
    {
        int maxIndex = 0;
        double maxHeight = 0;
        int idx = 0;
        while (idx < columnHeight.Length)
        {
            if (columnHeight[idx] > maxHeight)
            {
                maxHeight = columnHeight[idx];
                maxIndex = idx;
            }
            idx++;
        }
        return maxIndex;
    }
}

我的用户控件的结构:

 <Grid x:Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="57"/>
            <RowDefinition Height="auto"/>              
        </Grid.RowDefinitions>
        <Grid x:Name="namePanel">
             <StackPanel x:Name="nameContainer">
                  <TextBlock>Lamia Mehreen</TextBlock>
                  <TextBlock>Monday at 12:02pm</TextBlock>
                  <Button/>
             </StackPanel>
        </Grid>
        <Border x:Name="hiddenPanel" Visibility="Collapsed" Grid.Row="1">
                <StackPanel x:Name="editPanel" Orientation="Horizontal">
                        <RichTextBox/>
                        <Button Margin="0" Foreground="{x:Null}" Style="{DynamicResource ButtonStyle1}" BorderThickness="0" Background="{x:Null}" BorderBrush="{x:Null}" Focusable="False" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="0" Width="37" Height="37"/>
                </StackPanel>
         </Border>
    </Grid>

我的工作代码

<ScrollViewer>
    <NewsFeedPanel:NewsFeedPanel DefaultWidth="300" VGap="5" HGap="5" Margin="0, 15, 0, 0">
        <DockPanel Background="Beige" Height="80">
            <TextBlock Text="2 ==> Beige" Width="300"/>
        </DockPanel>
        <DockPanel Background="Blue" Height="80">
            <TextBlock Text="3 ==> Blue" Width="300"/>
        </DockPanel>
        <DockPanel Background="Yellow" Height="120">
            <TextBlock Text="4 ==> Cornsilk" Width="300"/>
        </DockPanel>
        <DockPanel Background="DarkGray" Height="40">
            <TextBlock Text="5 ==> DarkGray" Width="300"/>
        </DockPanel>
        <DockPanel Background="RosyBrown" Height="30">
            <TextBlock Text="6 ==> RosyBrown" Width="300"/>
        </DockPanel>
        <DockPanel Background="Cyan" Height="60">
            <TextBlock Text="7 ==> Cyan" Width="300"/>
        </DockPanel>
        <DockPanel Background="Green" Height="150">
            <TextBlock Text="8 ==> Green" Width="300"/>
        </DockPanel>
        <DockPanel Background="Gold" Height="90">
            <TextBlock Text="9 ==> Gold" Width="300"/>
        </DockPanel>
        <DockPanel Background="Violet" Height="40">
            <TextBlock Text="10 ==> Violet" Width="300"/>
        </DockPanel>
        <DockPanel Background="SkyBlue" Height="90">
            <TextBlock Text="11 ==> SkyBlue" Width="300"/>
        </DockPanel>
    </NewsFeedPanel:NewsFeedPanel>
</ScrollViewer>

我的代码不起作用

 <ScrollViewer>
    <control:NewsFeedPanel DefaultWidth="640" VGap="5" HGap="5" Margin="0, 15, 0, 0">
        <ItemsControl ItemsSource="{Binding MyCollection}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <uc:UCNewsFeed  Width="640"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </control:NewsFeedPanel>
</ScrollViewer>

自定义面板中的项目未正确排列

这个解决方案是世界上最简单的。我需要将 NewsFeedPanel 用作 ItemsPanel 而不是 wrapPanel。感谢克莱门斯的建议。