如何在水平环绕面板中排列WPF项目,以便它们根据每个项目中的任意垂直点排列?

时间:2010-05-22 15:15:20

标签: wpf listview mvvm wrappanel

我正在尝试在WPF中创建一个View,并且很难弄清楚如何设置它。这是我正在努力建立的:

  • 我的ViewModel公开了一个名为Items
  • 的IEnumerable属性
  • 每个项目都是时间轴上的事件,每个项目都实现了ITimelineItem
  • 每个项目的ViewModel都有自己的DataTemplate来显示它
  • 我想显示由一条线连接的时间轴上的所有项目。我认为ListView中的WrapPanel可以很好地用于此。
  • 但是,每个项目的高度将根据其显示的信息而有所不同。有些项目会在线条上有图形对象(如圆形或菱形等),有些项目的上方或下方有注释。

所以这对我来说似乎很复杂。似乎时间轴上的每个项目都必须呈现其自己的线段。没关系。但是项目顶部与线条之间的距离(以及项目底部与线条之间的距离)可能会有所不同。如果一个项目从顶部向下50 px,而下一个项目从顶部向下100 px,那么第一个项目需要50 px的填充,以便线段加起来。

我想我可以解决这个问题,但是,如果这两个项目在WrapPanel的同一行上,我们只需要添加填充!假设有5个项目,屏幕上只有3个空间... WrapPanel将把另外两个放在下一行。没关系,但这意味着只有前3个需要填充,最后2个需要填充。

这让我很头疼。还有其他方法我可以看一下吗?

编辑:我倾向于使用继承自Canvas的自定义面板替换WrapPanel,并覆盖MeasureOverride和ArrangeOverride方法。

2 个答案:

答案 0 :(得分:2)

理想的解决方案可能是使用Adorners。在AdornerLayer上,您可以为Panel上的每个项目设置一个自定义Adorner(您可以在DataTemplate中定义它)。您将能够检索每个项目的位置(Adorner的Boundingbox)。同样在AdornerLayer上,您将在这些边界框之间绘制线条。 使用此解决方案,您可以按照您想要的任何方式布置项目(使用您想要的任何面板),项目仍将与线条连接。

很久以前我将这种方法用于图形可视化工具。可以以任何方式布置仲裁UIElements的节点。与行连接的项目。

要使所有项目完美对齐,您可以使用Canvas作为ItemTemplate中的根面板。 Canvas可以是0x0单位。然后,您将在Canvas周围排列元素。画布成为您的参考点。该行顶部的所有内容都将获得负面的Canvas.Top值。 另一种方法是使用负边距,该边距限制在线上的顶部和底部控件的高度。使用IValueConverter(高度* -1)反转高度。

答案 1 :(得分:1)

这不会解决你的问题,但我敢打赌它会简化它:

尝试定义看起来像这样的DataTemplate

<Grid>
   <Grid.RowDefinitions>
      <RowDefinition Height="Auto" SharedSizeGroup="Top"/>
      <RowDefinition Height="10"/>
      <RowDefinition Height="Auto" SharedSizeGroup="Bottom"/>
   </Grid.RowDefinitions>
   <ContentControl Grid.Row="0" Content="{Binding TopAnnotations}/>
   <Rectangle Fill="Black" Grid.Row="1" Margin="0,4,0,4"/>
   <ContentControl Grid.Row="1" Height="10" Content="{Binding GraphicObject}"/>
   <ContentControl Grid.Row="2" Content="{Binding BottomAnnotations}"/>
</Grid>  

现在创建一个ItemsControlItemsPanelTemplate是一个水平WrapPanelGrid.IsSharedSizeScope附加属性设置为True。当然,您还需要为注释和图形对象属性包含的内容定义数据模板。

你仍然遇到这样的问题:当WrapPanel换行中的项目时,时间轴上方和下方的对象具有相同的填充,而不管它们实际需要在{{1 }}。因此,为了获得我认为你正在寻找的效果,你仍然需要谨慎对待并安排 - 基本上,你不会创建一个单独的WrapPanel,而是创建一些将这些项放入{ {1}}在每个“行”上,每个“行”都是自己的共享大小范围。但实际上,测量和排列时间轴项目的高度并不是您需要担心的事情。您只需要它们的宽度(这样您的逻辑就可以确定何时换行)。 WrapPanel会为您计算高度。