您好我需要一个包含多列和可变高度行的视图。我写了一个自定义的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>
答案 0 :(得分:0)
解决方案是世界上最简单的解决方案。我需要使用NewsFeedPanel作为ItemsPanel而不是wrapPanel。谢谢Clemens的建议。