自动高度与最大高度的组合

20

我遇到了一个问题,需要设置以下XAML布局:

RowHeightAuto.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="GridMaxHeight.RowHeightAuto"
    Title="RowHeightAuto" WindowState="Maximized">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto" MaxHeight="200" />
    </Grid.RowDefinitions>

    <StackPanel Background="LightGray" Grid.Row="0"></StackPanel>
    <DataGrid Name="DataGrid1" Grid.Row="1" />
</Grid>

DataGrid1控件在定义了许多列和行后没有显示任何滚动条。当我将Height="Auto"替换为Height="*"时,一切正常,水平和垂直滚动条就像预期的那样出现了。

如果我在DataGrid1中直接声明MaxHeight,它也能正常工作,但这并不是我真正想要的。

是子控件在设置Height="Auto"时忽略了maxheight的一个bug,还是我可能做错了什么?ListBox/ListView等也可以重现相同的行为,第三方控件如ComponentOne、Telerik也是如此。

如果这是一个bug - 你知道解决方法或者其他提示吗?

这里是我如何设置DataGrid的ItemsSource的代码。RowHeightAuto.xaml.cs

public partial class RowHeightAuto : Window
{
    private readonly DateTime _start;

    public RowHeightAuto()
    {
        InitializeComponent();

        DataGrid1.ItemsSource = GetTestData();

        _start = DateTime.Now;
        Dispatcher.BeginInvoke(new Action(() => MessageBox.Show((DateTime.Now - _start).TotalSeconds.ToString(CultureInfo.InvariantCulture))), DispatcherPriority.ContextIdle, null);
    }

    public static List<TestData> GetTestData()
    {
        const int maxCols = 501;
        const int maxRows = 300;

        var testDatas = new List<TestData>(maxRows);
        for (int i = 0; i < maxRows; i++)
            testDatas.Add(new TestData());

        for (int i = 0; i < maxCols; i++)
        {
            string propName = string.Format("Property{0}", AddLeadingZeros(i));

            for (int j = 0; j < maxRows; j++)
                testDatas[j][propName] = propName;
        }

        return testDatas;
    }

    private static string AddLeadingZeros(int val)
    {
        return val.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0');
    }
}

public class TestData
{
    public object this[string propertyName]
    {
        get
        {
            var myType = GetType();
            var myPropInfo = myType.GetProperty(propertyName);
            return myPropInfo.GetValue(this);
        }
        set
        {
            var myType = GetType();
            var myPropInfo = myType.GetProperty(propertyName);
            myPropInfo.SetValue(this, value, null);

        }
    }

    public string Property000 { get; set; }
    public string Property001 { get; set; }
    public string Property002 { get; set; }
    public string Property003 { get; set; }
    ...
    public string Property498 { get; set; }
    public string Property499 { get; set; }
    public string Property500 { get; set; }

}

1
一个格式良好且有文档说明的第一个问题会得到+1。欢迎来到SO :) - Viv
1
请注意,您可以编写 string.Format("Property{0:000}", i) 而不是调用您的 AddLeadingZeros 方法。 - Clemens
@ Viv:谢谢。@ Clemens:感谢您的建议。我对字符串格式不熟悉。 :) - Rand Random
1个回答

12

正如你所说的那样。

你看不到 Scrollbar 的原因是因为即使 GridDataGrid 裁剪,它仅仅是一个裁剪,DataGridActualHeight 是它的所有子元素都可以显示的高度。因此,你没有看到它的滚动条。ActualHeight 是这样的,因为 Grid 上有 Height="Auto",它被允许获取所有它想要的空间。我的个人理由不认为这是一个 bug 是因为你可能希望在某些动画中使用 GridClipToBounds 属性并且这是你想要的行为。考虑了这一点,我实际上认为从 "不可取的功能" 的角度来看,我也会将其称为 bug 而不是 "不正确的输出"。

为了获得你想要的行为,

  • DataGrid 上应用 MaxHeight 或使用 Grid RowDefinition.Height="*" <- 都像你提到的那样(不确定为什么你说这不是你想要做的?)
  • 或者你也可以在 DataGrid 上使用 RelativeSourceBinding

像这样 -

<DataGrid Name="DataGrid1" 
          Grid.Row="1"
          Height="{Binding RelativeSource={RelativeSource FindAncestor,
                           AncestorType={x:Type Grid}},
                           Path=RowDefinitions[1].ActualHeight}">

如果遇到这种问题,Snoop 是您的好帮手。您可以使用 Snoop 轻松地检查此行为,并了解为什么在检查 DataGrid 上的 ActualHeight 时未显示滚动条,并且看到它为子控件分配了更多的高度。


我真的不明白为什么会发生这种情况,在我的布局中,我明确声明只想要一个最大高度为200。 您能否解释一下为什么有人在声明MaxHeight时希望完全大小的子元素呢?还有可能有一个原因,为什么即使水平滚动条也没有显示出来,这对我来说绝对没有意义。 - Rand Random
但你也在说 Height="Auto",这意味着“占用你想要的所有空间”。这只是我的个人意见。你可以在 MSDN 上提出一个 bug 并问他们为什么指定自动高度不会强制子控件尊重 Grid.RowDefinition 上的 MaxHeight。对我来说,如果你将 Height 指定为 "*",那么子控件就可以从父控件中获取“任何可用空间”,这可能会被 MaxHeight 限制,因此输出结果就是你所期望的。 - Viv
@RandRandom ..续。然而,当您设置Height="Auto"时,存在不匹配的情况,其中Grid的一行被强制仅通过MaxHeight采用200 ActualHeight,而子项可以通过高度的自动调整来占据任意空间,当子项需要的空间与该Grid行符合其所给定的最大值200时,两者都满足要求。 - Viv
@RandRandom 关于水平滚动条,它与此问题无关,只是副作用的无辜受害者。水平滚动条在高度上超出了200,因此您看不到它。但它始终位于DataGrid的底部末端。 - Viv

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