WPF:同步ItemsControl中所有项的宽度

8
是否可以调整WrapPanel中所有TextBlock的宽度,使其与WrapPanel中最大的TextBlock相同?最终结果应该是包含“Some data”文本的控件具有与包含“Even more data than before.”文本的控件相同的宽度。我已经附加了我的初始代码作为起点。我使用字符串作为示例,但集合数据和模板可以是任何内容,因此我不能依赖于字符串的长度。
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Collections:ArrayList x:Key="data">
            <System:String>Some data</System:String>
            <System:String>Some more data</System:String>
            <System:String>Even more data than before</System:String>
        </Collections:ArrayList>
    </Window.Resources>
    <ItemsControl ItemsSource="{StaticResource data}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel></WrapPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border Margin="5" BorderThickness="1" BorderBrush="Black">
                    <TextBlock Text="{Binding}"></TextBlock>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

“所需输出的图像:”

Desired output

4个回答

20

使用共享大小网格:

<ItemsControl ItemsSource="{StaticResource data}" Grid.IsSharedSizeScope="True">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel></WrapPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="ColumnSize" />
                </Grid.ColumnDefinitions>
                <Border Margin="5" BorderThickness="1" BorderBrush="Black">
                    <TextBlock Text="{Binding}"></TextBlock>
                </Border>
            </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

所有列都保证具有相同的宽度,因为它们共享一个大小组。由于它们是自动调整大小的,它们也会调整大小以适应网格中任何内容的最大实例。


相当优雅的解决方案。这个解决方案非常好地解决了我的问题,而且无需编写任何自定义代码。对于这个答案,您是否立即想到任何限制? - mortalapeman

4
你需要创建一个源自wrappanel的自定义版本,以实现你想要的效果。通常情况下,对于自定义面板,你需要重写以下两个方法:
- MeasureOverride - ArrangeOverride 在你的情况下,你需要使用MeasureOverride来迭代元素并查找最大的元素,然后在ArrangeOverride中为所有元素使用相同的大小。有关如何创建自定义面板的更多信息,请参见:http://www.wpftutorial.net/CustomLayoutPanel.html

一个具有略微修改的Wrap Panel特性的自定义面板是我认为我必须妥协的选择,但直到我看到@TobyCrawford提出的答案。 - mortalapeman

2
您可以在itemsPanel中添加HorizontalContentAlignment=Stretch,并添加UniformGrid。
 <Window.Resources>
    <Collections:ArrayList x:Key="data">
        <System:String>Some data</System:String>
        <System:String>Some more data</System:String>
        <System:String>Even more data than before</System:String>
    </Collections:ArrayList>
</Window.Resources>
<ListBox ItemsSource="{StaticResource data}" HorizontalContentAlignment="Stretch">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <UniformGrid IsItemsHost="True"></UniformGrid>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border Margin="5" BorderThickness="1" BorderBrush="Black" >
                <TextBlock Text="{Binding}" Width="{Binding 
            RelativeSource={RelativeSource TemplatedParent},
            Path=Width}"></TextBlock>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

UniformGrid,解决的问题比你想象的要多。 - user1228
在我看来,IMHO不符合OP的要求。如果他调整窗口大小会怎样? - Philip Stuyck
在看到这篇文章之前,我不知道UniformGrid,谢谢你。不幸的是,我必须同意@PhilipStuyck的观点,即它没有与Wrap Panel相同的调整大小特性。 - mortalapeman

1
这是对Philip Stuyck的自定义面板建议的一种替代方案,您可能会发现这更适合您特定的情况。(诚然,这有点像一个hack。)
您可以使用FormattedText类计算字符串的长度。因此,您可以遍历字符串并计算最大长度(这也假定您知道字体系列和大小)。然后只需将文本块的宽度绑定到最大宽度即可。我会在父级别存储宽度值,然后使用RelativeSource绑定:
<TextBlock Text="{Binding}" 
           Width="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl},
                           Path=MaximumWidth}}" 
       />

(这种方法的一个缺点是,如果项目集合发生更改,您将不得不重新计算最大宽度。)

很遗憾,我无法计算字符串的长度,因为我的真正问题与字符串无关,我只是用它们作为一个例子。我曾考虑过某种祖先宽度绑定,但希望有更优雅的解决方案。不过,知道可以用这种方式做到仍然很好。 - mortalapeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接