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

时间:2015-06-17 12:33:15

标签: c# wpf xaml

您好我需要一个包含多列和可变高度行的视图。我写了一个自定义的WrapPanel,如果明确给出它的子代,它可以正常工作。当我在DataTemplate中提供带有UserControl的ItemsControl作为WrapPanel的孩子时会出现问题。

我的CustomWrapPanel:

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

}

我的UserControl的结构:

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

1 个答案:

答案 0 :(得分:0)

解决方案是世界上最简单的解决方案。我需要使用NewsFeedPanel作为ItemsPanel而不是wrapPanel。谢谢Clemens的建议。