WPF:调整项目大小以使所有项目可见

WPF:调整项目大小以使所有项目可见,wpf,xaml,Wpf,Xaml,我有以下代码: <ItemsControl ItemsSource="{Binding SubItems}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal"></WrapPanel> </ItemsPanelTemplate> <

我有以下代码:

<ItemsControl ItemsSource="{Binding SubItems}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"></WrapPanel>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid   Margin="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"></RowDefinition>
                    <RowDefinition Height="Auto"></RowDefinition>
                </Grid.RowDefinitions>
                <Image Source="{Binding Image}" ></Image>
                <TextBlock Text="{Binding Name}" Grid.Row="1"  HorizontalAlignment="Center"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

当前,如果我运行此代码,每个项目(网格)都会尝试占用全部可用空间,在我的
子项目
集合中的20多个项目中,我只有1-2个项目可见

如果我将
MaxWidth
设置为我的网格,我会看到所有的窗口,但是当我最大化窗口时,我有很多可用空间

如果我没有设置任何宽度,我会:

如果我设置了宽度并增加了大小,我会:

我们的目标是拥有类似于第二种情况的东西,但不必设置宽度,如果我增加窗口大小,就可以缩放它

Edit2 我尝试使用UniformGrid,但有两个问题。对于两个元素,它似乎绝对希望有4列和3行。即使使用3列4行也会更好:

此外,当窗口缩小时,图像将被剪切:

您需要更改
行定义
,使其看起来更像这样

<RowDefinition Height="*"/>

您的一行被设置为
Auto
,这将尝试只填充它所需的空间。另一个设置为
*
,这将自动拉伸以填充所有空间

请注意,也不需要键入
,只需以
/>
结尾即可。此链接可能对您特别有用

你可以试试这个

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <UniformGrid />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>


如果没有其他帮助,请考虑编写自己的面板。我现在没有时间做一个完整的解决方案,但是考虑一下。 首先,以您想要的方式平铺矩形和正方形不是很简单。这就是所谓的包装问题,通常很难找到解决方案(取决于具体问题)。我已使用算法从以下问题中找到近似的磁贴大小:

当面板的给定宽度和高度为正方形时,其余部分更容易:

公共类可调整包装面板:面板{
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸){
//获取瓷砖大小
var tileSize=GetTileSize((int)availableSize.Width,(int)availableSize.Height,this.InternalChildren.Count);
foreach(此.InternalChildren中的UIElement子元素){
//用每个孩子应该占据的正方形来测量他们
测量(新尺寸(瓷砖大小,瓷砖大小));
}
返回可用性;
}
受保护的替代尺寸排列替代(尺寸最终化){
var tileSize=GetTileSize((int)finalSize.Width,(int)finalSize.Height,this.InternalChildren.Count);
int x=0,y=0;
foreach(此.InternalChildren中的UIElement子元素)
{
//摆正
排列(新矩形(新点(x,y),新大小(平铺大小,平铺大小));
x+=波浪形;
如果(x+tileSize>=finalSize.Width){
//如果需要移动到下一排,请这样做
x=0;
y+=波浪形;
}
}
返回最终化;
}
int GetTileSize(int-width、int-height、int-tileCount)
{
if(宽度*高度
创建数据模板,如下所示:

<DataTemplate>               

   <Grid Height="{Binding RelativeSource={RelativeSource Self},Path=ActualWidth,Mode=OneWay}">
     <Grid.Width>
       <MultiBinding Converter="{StaticResource Converter}">
          <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="ActualWidth" Mode="OneWay" />
          <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="ActualHeight" Mode="OneWay" />
          <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="DataContext.SubItems.Count" />                            
          <Binding RelativeSource="{RelativeSource AncestorType=ItemsControl}" Path="ActualWidth" />
       </MultiBinding>
     </Grid.Width>                    
     <Grid.RowDefinitions>

转换器:

公共类转换器:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
double TotalWidth=System.Convert.ToDouble(值[0]),TotalHeight=System.Convert.ToDouble(值[1]);
int TotalItems=System.Convert.ToInt32(值[2]);
var TotalArea=总宽度*总高度;
var AREA SOFANITEM=总面积/总项目;
var SideOfitem=Math.Sqrt(A
 public class Converter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double TotalWidth = System.Convert.ToDouble(values[0]), TotalHeight = System.Convert.ToDouble(values[1]);
        int TotalItems = System.Convert.ToInt32(values[2]);           
        var TotalArea = TotalWidth * TotalHeight;
        var AreasOfAnItem = TotalArea / TotalItems;           
        var SideOfitem = Math.Sqrt(AreasOfAnItem);
        var ItemsInCurrentWidth = Math.Floor(TotalWidth / SideOfitem);
        var ItemsInCurrentHeight = Math.Floor(TotalHeight / SideOfitem);
        while (ItemsInCurrentWidth * ItemsInCurrentHeight < TotalItems)
        {
            SideOfitem -= 1;//Keep decreasing the side of item unless every item is fit in current shape of window
            ItemsInCurrentWidth = Math.Floor(TotalWidth / SideOfitem);
            ItemsInCurrentHeight = Math.Floor(TotalHeight / SideOfitem);
        }
        return SideOfitem;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}