【问题标题】:Limit maximum width of "Auto" column in WPF data grid限制 WPF 数据网格中“自动”列的最大宽度
【发布时间】:2013-01-05 21:29:33
【问题描述】:

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

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

我想要实现的是第二列根据其内容自动调整大小,第一列获得所有剩余空间。但是我也希望第一列永远不会少于 200 像素。问题是使用这种配置我的自动列将被切断而不是调整大小。

我真正想要的是 WPF 首先为第一列分配 200 个像素,然后占用所有剩余空间并要求第二列的内容调整自身大小,并限制剩余宽度的最大大小。如果内容需要较少的空间,则应将剩余空间分配给第一列(使其大于 200 像素)。

用例:我的第二列是具有固定纵横比的图像,因此对于给定的高度,存在最佳宽度。我还有第一列,其中包含一些应该始终可见的控件。如果可用空间比需要的多,我想将空间分配给第一列而不是第二列。

有没有办法使用默认的 WPF 控件来实现这一点,还是我需要为此编写自己的 Grid?

【问题讨论】:

    标签: .net wpf xaml layout resize


    【解决方案1】:

    听起来您想要的基本上是为您的第二列提供 2 种不同的模式。当整个图像有足够的空间以当前高度显示时,它应该是自动的,否则它应该在第一列取 200 后获得剩余空间。要进行这种模式切换,您可以使用转换器并绑定列的宽度。

    这里有 2 个基本输入:网格可用的总大小和所需的图像宽度。因为你需要它们,所以你需要一个 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>
    

    【讨论】:

    • 我想这会起作用,但说实话,我真的厌倦了在 WPF 中编写数千个转换器。我希望有一些开箱即用的东西。
    【解决方案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>
    

    【讨论】:

      【解决方案3】:

      我唯一一次看到第二列被截断是当第二列的宽度 + 200 大于网格的宽度时。我玩过,也许这对你来说是一个解决方案:

      <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>
      

      我尝试写&lt;ColumnDefinition Width="Auto" MaxWidth="400"/&gt;,但当时maxwidth没有效果。

      Viewbox 的 MaxWidth 计算为总宽度 - 如果不明显,则保留 200。

      【讨论】:

      • 那么问题是:由于我不知道之前的总宽度(600),因为它是由窗口大小决定的,我如何计算网格的 MaxWidth?我想我可以为此编写一个转换器,但如果有更直接的方法会更好......
      • 我不知道,但我会关注这个问题。如果您觉得这会损害您获得更好答案的机会,我可以删除。我也不喜欢转换器。
      • 请不要删除答案。我想我已经知道如何根据您的版本在不使用转换器的情况下解决这个问题。
      • 好了,我做的如下。这也是一个有点脏的工作方法,但它避免了转换器:平行于网格我插入了一个占位符控件,该控件伸展到与网格相同的大小。占位符的边距设置为 200 像素(第一列的 MinWidth)。像这样,(不可见)占位符的宽度将等于第二列的最大允许宽度。因此,我可以将其绑定到此占位符控件的 ActualWidth ,而不是将 MaxWidth 设置为您的示例中的固定值。也许您可以将其包含在您的答案中。
      猜你喜欢
      • 2016-05-09
      • 2017-12-05
      • 2011-11-08
      • 1970-01-01
      • 2012-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      相关资源
      最近更新 更多