如何在当前高度为0的情况下获取WPF UI元素所需的高度?

4
我的最终目标是实现两个UserControls之间大小变化的动画。我尝试过的方法产生了一个主要问题。
我从包含一些基本文本和图标显示的DataTemplate开始,有一个高度设置为0的“edit”UserControl和一个编辑按钮。该编辑UserControl在一个GridRow中,其Height="Auto",因此它的高度也从0开始。按钮有一个DoubleAnimation,由按钮单击触发,将UserControl的高度从0动画到300。这一切都运作得很好。以下是一个简化的代码示例。
<DataTemplate x:Key="UserTemplate" DataType="{x:Type dataTypes:User}">
...
<controls:UserView Grid.Row="1" Grid.ColumnSpan="5" x:Name="EditRow" 
    DataContext="{Binding}" Height="0" />
<controls:UserEditor Grid.Row="2" Grid.ColumnSpan="5" x:Name="EditRow" 
    DataContext="{Binding}" Height="0" />
<Button Grid.Row="0" Grid.Column="4" Name="Edit" Style="{StaticResource ButtonStyle}" 
    ToolTip="Edit user" Click="Button_Click">
    <Image Source="/SolutionName;component/Images/Edit.png" Stretch="None" />
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.Click">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Name="EditRowHeightAnimation" 
    Storyboard.TargetName="EditRow" Storyboard.TargetProperty="Height" From="0" 
    To="300" Duration="00:00:0.5" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>
...
</DataTemplate>

问题在于编辑用户控件的高度不是300像素,而且我在设计时也不知道它的高度。我尝试了以下方法,但没有成功。
<DoubleAnimation Name="EditRowHeightAnimation" Storyboard.TargetName="EditRow"
    Storyboard.TargetProperty="Height" From="0" To="{Binding DesiredSize.Height, 
    ElementName=EditRow}" Duration="00:00:0.5" />

我还尝试从代码后台调用编辑UserControl的Measure()和UpdateLayout()方法。我注释了按钮单击触发器和xaml动画,并添加了一个从代码后台触发的触发器...现在这种方式有点奏效,但我始终得到相同(错误的)DesiredSize。也就是说,UserControl的高度会被动画化,但仅仅是到错误的高度。下面是按钮单击处理程序代码。

private void Button_Click(object sender, RoutedEventArgs e)
{
    User currentUser = (User)CollectionViewSource.GetDefaultView(Users).CurrentItem;
    ListBoxItem listBoxItem = (ListBoxItem)
        (UsersListBox.ItemContainerGenerator.ContainerFromItem(currentUser));
    DataTemplate itemDataTemplate = FindResource("UserTemplate") as DataTemplate;
    ContentPresenter contentPresenter = listBoxItem.GetInternal<ContentPresenter>();
    if (itemDataTemplate != null && contentPresenter != null)
    {
        UserEditor userEditor = (UserEditor)itemDataTemplate.FindName("EditRow", 
            contentPresenter);
        userEditor.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        userEditor.UpdateLayout();
        userEditor.BeginAnimation(HeightProperty, new DoubleAnimation(0, 
            userEditor.DesiredSize.Height, new Duration(new TimeSpan(0, 0, 1)), 
            FillBehavior.HoldEnd), HandoffBehavior.Compose);
    }
}

我想知道如果UserControl的容器没有对其施加尺寸限制,当它的当前高度为0时,如何获取其大小?

如果有更好的方法实现我的最终目标,也欢迎分享。谢谢。


我曾经遇到过类似的问题,解决方法是在你想要获取所需高度的UserControl的父级上调用UpdateLayout...我也曾经卡在了对UserControl本身调用Measure的问题上。父级的UpdateLayout将测量和排列所有子控件,并给出了我所需的确切高度,记得考虑边距/填充;) - Youp Bernoulli
2个回答

7
您可以将想要的尺寸内容放入一个带有“ClipToBound="True"”属性的Canvas中。然后,您可以操纵Canvas的大小,而Canvas内部内容的大小始终保持其完整的所需大小。

嘿,Rick,我相信你以前帮过我……我再也无法感谢你了!我被卡在这里很长时间了,只是知道一定有一个简单的解决方案!再次感谢。对于任何跟进此事的人,使用建议的画布使我能够将 DoubleAnimation.To 属性绑定到我的 UserControlActualHeight 属性上。现在它会正确地滑开到所需大小。 - Sheridan
处理一个非常相似的问题 :( 您在哪里使用画布?在 XAML 中还是在代码后台? - Youp Bernoulli

3
也许更容易的方法是将目标的LayoutTransform.ScaleY从0动画到1,因为所需高度始终为1,不需要额外的控件。

那是我一开始做的,但我不喜欢效果的外观。无论如何,谢谢。 - Sheridan

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