限制WPF数据网格中“自动”列的最大宽度

6

我有一个标准的WPF网格,其中定义了2列:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" MinWidth="200" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    ...
</Grid>

我想要实现的是让第二列根据其内容自动调整大小,而第一列则占据所有剩余空间。然而,我也希望第一列的宽度不小于200像素。问题在于,使用这种配置时,我的自动列会被截断而不是被调整大小。
我真正想要的是,WPF首先将200像素分配给第一列,然后取所有剩余空间,并请求第二列的内容以最大尺寸限制自行调整大小。如果内容需要更少的空间,则应将剩余空间分配给第一列(使其大于200像素)。
用例:我的第二列是一个具有固定纵横比的图像,因此对于给定的高度,存在一个最佳宽度。我还有一个第一列,其中包含一些应始终可见的控件。如果有多余的空间可用,我希望将空间分配给第一列而不是第二列。
是否有一种使用默认WPF控件实现此目的的方法,还是我需要为此编写自己的网格?
3个回答

2

试一下
设置最大宽度

<Grid Height="200"
          Width="600">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"
                          MaxWidth="200" />
        <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>
      <Border Background="Blue"
              Grid.Column="0" />
      <Viewbox Grid.Column="1"
               Stretch="Uniform"
               MaxWidth="400">
        <Border Background="Yellow"
                BorderBrush="Red"
                BorderThickness="4"
                Height="200"
                Width="300" />
      </Viewbox>
    </Grid>

2
似乎您想要的是第二列有两种不同的模式。当足够的空间可以显示整个图像时,它应该是自动的;否则,它应该只获取第一列占用200后剩余的空间。为了进行这种模式切换,您可以使用转换器并绑定列的宽度。
您需要两个基本输入:网格可用的总大小和图像的期望宽度。由于您需要它们两个,因此您需要一个IMultiValueConverter。下面是一个基本实现,可以计算上述的开关:
public class AutoColumnConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double imageWidth = values.OfType<double>().FirstOrDefault();
        double gridWidth = values.OfType<double>().ElementAtOrDefault(1);
        int minWidth = System.Convert.ToInt32(parameter);

        double availableSpace = gridWidth - minWidth;
        if (imageWidth > availableSpace)
            return new GridLength(availableSpace, GridUnitType.Pixel);

        return new GridLength(0, GridUnitType.Auto);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

要使用此功能,您需要将Grid包装在另一个元素中,而不是直接绑定到Grid本身,这样它就可以欺骗可用空间并尝试通过两个定义的列进一步拉伸。在这里,我使用Source.Width来查找图像所需的宽度。如果您更关心纵横比或其他方面的高度,请进行调整。

<Border>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" MinWidth="200" />
            <ColumnDefinition>
                <ColumnDefinition.Width>
                    <MultiBinding ConverterParameter="200">
                        <MultiBinding.Converter>
                            <local:AutoColumnConverter/>
                        </MultiBinding.Converter>
                        <Binding ElementName="Img" Path="Source.Width"/>
                        <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Border}}" Path="ActualWidth"/>
                    </MultiBinding>
                </ColumnDefinition.Width>
            </ColumnDefinition>
        </Grid.ColumnDefinitions>

        <Image x:Name="Img" Grid.Column="1" Stretch="Uniform" StretchDirection="DownOnly"
                Source="..."/>
    </Grid>
</Border>

6
我认为这个方法是可行的,但说实话,我已经厌倦了在WPF中编写数千个转换器。我希望有一些开箱即用的东西。 - aKzenT

1
我只在列2的宽度加上200大于网格的宽度时才看到列2被切断。我尝试了一下,也许这对你有帮助:
<Grid Height="200"
      Width="600">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"
                      MinWidth="200" />
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <Border Background="Blue"
          Grid.Column="0" />
  <Viewbox Grid.Column="1"
           Stretch="Uniform"
           MaxWidth="400">
    <Border Background="Yellow"
            BorderBrush="Red"
            BorderThickness="4"
            Height="200"
            Width="300" />
  </Viewbox>
</Grid>

我尝试编写<ColumnDefinition Width="Auto" MaxWidth="400"/>,但maxwidth没有效果。

对于Viewbox,MaxWidth是通过总宽度减去保留的200来计算的,如果这不明显的话。


那么问题是:由于我不知道之前的总宽度(600)是由窗口大小确定的,那么我如何计算网格的MaxWidth?我猜我可以为此编写一个转换器,但如果有更直接的方法会更好... - aKzenT
我不知道,但我会关注这个问题。如果您觉得它会影响您获得更好的答案的机会,我可以删除它。我也不喜欢转换器。 - Johan Larsson
请不要删除答案。根据您的版本,我认为我已经有了解决此问题而无需转换器的想法。 - aKzenT
好的,我所做的是以下内容。这也有点不太正规,但它避免了转换器:在网格中并行插入一个占位符控件,该控件会拉伸以具有与网格相同的大小。占位符设置了200像素的边距(第一列的MinWidth)。这样,(不可见的)占位符的宽度将等于第二列允许的最大宽度。因此,我可以将MaxWidth绑定到此占位符控件的ActualWidth,而不是像您的示例中那样设置为固定值。也许您可以在您的答案中包含这个方法。 - aKzenT

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