WPF可展开控件标题水平拉伸

15

我在Wpf中有一个Expander。标题上我有一个左对齐的标签,想在右侧放置一个按钮。我使用以下XAML:

<Expander HorizontalAlignment="Stretch" IsExpanded="True">
    <Expander.Header >
        <Grid HorizontalAlignment="Stretch" Background="Aqua" Margin="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Content="Label on the left site"/>
            <Button Grid.Column="1" Content="Button on the right"/>
         </Grid>
    </Expander.Header>
    <Label Content="Some Content"/>
</Expander>

但是那样做行不通。头部的按钮与标签相邻并靠左对齐。 有人能解释一下如何正确地做吗?


4
在一个可扩展的标题中拉伸内容本文介绍如何在WPF (Windows Presentation Foundation) 中创建一个可扩展的UI控件,使其打开和关闭时可以动态地拉伸和缩小其标题中的内容。该控件可以方便地用于展示可折叠的信息。在XAML中,可以使用ToggleButton、Grid、ColumnDefinition和ContentPresenter等元素来实现这个可扩展控件。通过设置Grid行高度为Auto,并将ContentPresenter放置在第二列中,就可以实现标题中内容的自适应大小。此外,可以使用Storyboard来处理标题栏的展开和收起动画效果。如果您需要在WPF应用程序中实现可扩展的视图控件,可以参考这个例子并进行相应的修改和定制。 - Bolu
5个回答

47

Expander 头部内容呈现器的水平对齐方式设置为 Left

您可以使用 OneWayToSource 绑定 HorizontalAlignment (默认情况下为 GridStretch)将其更改为 Stretch,如下所示:

<Expander>
    <Expander.Header>
        <Grid Background="Yellow">
            <TextBlock Text="Header"
                       HorizontalAlignment="{Binding HorizontalAlignment, RelativeSource={RelativeSource AncestorType=ContentPresenter}, Mode=OneWayToSource}" />
        </Grid>
    </Expander.Header>
</Expander>

P.S.:我花了比应该要多的时间才理解了被接受答案的解决方案,所以我决定为将来的读者节省时间。


5
这应该被接受作为答案,因为它并未建议您需要更改标题模板。 - Mateusz Myślak
这是唯一有效且干净的答案,应该被接受。 - christopher_h
3
我同意这应该是被接受的答案。但是绑定应该在Grid上定义,而不是在TextBlock上。 - Till F.
ContentPresenter 上的对齐方式帮了我大忙。在我的自定义扩展模板中修复了它,et voila! - Travis
那太完美了! - Flou
显示剩余2条评论

22

使用下面提供的XAML,我成功实现了标题中内容的拉伸。基本上,我将网格的HorizontalAlignment数据绑定到ContentPresenter祖先。不幸的是,Scher提供的解决方案(数据绑定到ActualWidth)可能会导致UI元素显示宽于其容器,从而导致控件被部分切断。Bolu对文章“在展开器标题中拉伸内容”的链接使用的是代码后台,而这个示例则使用纯XAML。

<ItemsControl x:Name="ItemGroups" Grid.Column="2" Grid.Row="0"   ItemsSource="{Binding Model.ItemGroups}" ScrollViewer.VerticalScrollBarVisibility="Auto" >
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Expander Margin="4,0"   Header="{Binding}">
                        <Expander.HeaderTemplate>
                            <DataTemplate>
                                <Grid  HorizontalAlignment="{Binding Path=HorizontalAlignment, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Mode=OneWayToSource}" >
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition   />
                                        <ColumnDefinition  Width="Auto"/>
                                        <ColumnDefinition  Width="64"/>
                                    </Grid.ColumnDefinitions>

                                    <TextBox Grid.Column="0"  Text="{Binding Name, Mode=TwoWay}" />
                                    <TextBlock Grid.Column="1" Text="{Binding TotalCostString}" Margin="4,0"/>
                                    <Button Grid.Column="2" Command="{Binding DataContext.RemoveItemGroup, ElementName=ItemGroups, Mode=OneWay}" CommandParameter="{Binding}" Content="Remove"/>
                                </Grid>         
                            </DataTemplate>
                        </Expander.HeaderTemplate>
                        <Expander.Content>
                            <TextBlock Text="{Binding Summary}"></TextBlock>
                        </Expander.Content>
                    </Expander>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

谢谢,我刚看到这个话题并看到了你的答案。我没有想到这一点,但我确认这有效。这是一些额外的XAML代码,但仅使用XAML很好。我还将其绑定到标题中的实际宽度,但那有点太大了。我可以使用转换器并调整边框的宽度(例如2像素),但那会更“静态”但代码更短 :) - juFo
这是否有效,因为Grid.HorizontalAlginment的默认值是Stretch - Tim Pohlmann
当展开按钮放在右侧时,此解决方案也适用,就像ray的答案中提到的那样。 - scher
我曾经遇到一个类似的问题,涉及自定义DataGrid表头,表头没有根据列宽度进行调整大小。我发现这里的方法也适用于DataGrid表头。 - Chris Tophski

10
我采用了Bolu提供的其中一种解决方案。以下是结果:
    <Expander HorizontalAlignment="Stretch" IsExpanded="True">
        <Expander.Header >
            <!-- Width-Binding is needed, to fill the whole header horizontally-->
            <Grid HorizontalAlignment="Stretch" Background="Aqua" Margin="0" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}}, Path=ActualWidth}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Content="Label on the left site"/>
                <!-- Margin is needed, to bring the Button into the view -->
                <Button Grid.Column="1" Content="Button on the right" Margin="0,0,40,0"/>
            </Grid>
        </Expander.Header>
        <Label Content="Some Content"/>
    </Expander>

1

*Heck: 将右边填充到例如100000:Padding="2 2 100000 2"

<Expander Name="Name" ExpandDirection="Down">
    <Expander.Header>
        <TextBlock Text="Expander..." Margin="0 5" Padding="2 2 100000 2" />
    </Expander.Header>
</Expander>

0

如果您不想完全改变Expander Header的外观,也可以使用Behaviors(System.Windows.Interactivity),在Header加载时修改HorizontalAlignment。

internal class StretchingExpanderHeaderBehavior : Behavior<Expander>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += StretchHeader;
    }

    private void StretchHeader(object sender, RoutedEventArgs e)
    {
        DependencyObject header = AssociatedObject.Header as DependencyObject;
        if (header != null)
        {
            ContentPresenter contentPresenter = VisualTreeHelper.GetParent(header) as ContentPresenter;
            if (contentPresenter != null)
            {
                contentPresenter.HorizontalAlignment = HorizontalAlignment.Stretch;
            }
        }
    }
}

这可以附加到扩展器上

<Expander>
    <Expander.Header>
        <DockPanel HorizontalAlignment="Stretch">
            <Button DockPanel.Dock="Right" Content="Button on the right" />
            <Label Content="Label on the left site"/>
        </DockPanel>
    </Expander.Header>

    <Border BorderBrush="LightGray" BorderThickness="1">
        <ItemsPresenter />
    </Border>

    <iy:Interaction.Behaviors>
        <bhv:StretchingExpanderHeaderBehavior />
    </iy:Interaction.Behaviors>

</Expander>

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