WPF 扩展器模板 - 在 ToggleButton 上方显示内容

WPF Expander Templating - Display Content above ToggleButton

我正准备通过创建不同的模板来创建一个新的 Expander 控件(学习目的),但无法弄清楚我做错了什么...

切换按钮模板:

<ToggleButton>
    <ToggleButton.Template>
        <ControlTemplate TargetType="ToggleButton">
            <Border x:Name="eBB" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                <Grid>
                    <Path x:Name="Sign" Data="M 0,10 L 7.5,2.5 L 15, 10" Stroke="Black" Width="15">
                        <Path.RenderTransform>
                            <RotateTransform Angle="0"/>
                        </Path.RenderTransform>
                    </Path>
                </Grid>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter Property="Data" TargetName="Sign" Value="M 0,2.5 L 7.5,10 L 15,2.5"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Stroke" Value="#222" TargetName="Sign"/>
                    <Setter Property="Background" Value="#666" TargetName="eBB"/>
                </Trigger>
                <Trigger Property="IsPressed" Value="True">
                    <Setter Property="Stroke" Value="#FF003366" TargetName="Sign"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </ToggleButton.Template>
</ToggleButton>

扩展器模板:

<Expander>
    <Expander.Template>
        <ControlTemplate TargetType="Expander">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition x:Name="ContentRow" Height="*"/>
                    <RowDefinition Height="20"/>
                </Grid.RowDefinitions>
                <ContentPresenter Grid.Row="0" Visibility="Collapsed" Content="{TemplateBinding Content}"/>
                <local:FullSizeExpanderToggleButton Grid.Row="1" />
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsExpanded" Value="True">
                    <Setter Property="Visibility" Value="Visible"/>
                    <Setter Property="Height" Value="*" TargetName="ContentRow"/>
                </Trigger>
                <Trigger Property="IsExpanded" Value="False">
                    <Setter Property="Height" Value="0" TargetName="ContentRow"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Expander.Template>
</Expander>

现在,当我想在我的主视图中添加扩展器时:

<custom:FullSizeExpander Width="300">
            <Button/>
        </custom:FullSizeExpander>

控件内的整个 space 被按钮填充(ToggleButton 不再可见)。

我做错了什么?

另外我对这个问题有一些疑问:

  1. "ContentSource="Content"" 有什么作用?它是做什么用的?与 "Content="{模板绑定内容}"" 有何不同?
  2. 当 ToggleButtons 属性 "IsPressed" 发生变化时,Expander 的 属性 "IsExpanded" 会发生变化吗?如果扩展器中根本没有切换按钮怎么办?

首先,考虑修改您的扩展器模板,使其看起来像这样:

 <Expander>
            <Rectangle Height="500" Width="500" Fill="Red"/>
            <Expander.Template>
                <ControlTemplate TargetType="Expander">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="20"/>
                        </Grid.RowDefinitions>
                        <ContentPresenter Grid.Row="0" x:Name="ContentPresenter"/>
                        <ToggleButton Grid.Row="1" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded}"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="True">
                            <Setter TargetName="ContentPresenter" Property="Visibility" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="IsExpanded" Value="False">
                            <Setter TargetName="ContentPresenter" Property="Visibility" Value="Collapsed"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Expander.Template>
        </Expander>

我将解释它是如何工作的,以及为什么它在 top-down 之前不起作用。 首先,您需要在扩展器中实际放置一些东西以确保它正常工作 - 我现在在这里放置一个固定大小的矩形。

接下来,我将第一个 RowDefinition 更改为 auto 而不是 *,因为您希望展开器在打开时实际展开。 (而不是仅仅将其内容隐藏在一个大的空白区域)。 Auto 使用行中内容所需的 space,因此当它折叠时,该大小将为 0,而当它展开时,auto 将变为 500 以适合矩形。

我做的第三件事是从 ContentPresenter 中删除您的绑定。碰巧的是,Windows' content-bearing 模板(就像任何可以在其中放置其他内容的东西一样)将自动在其模板中查找第一个 ContentPresenter / ItemsPresenter 标签并将内容推送到其中。

然而至于切换按钮(我保持简单并将其保留为标准切换按钮),这个确实需要绑定。 我所做的是绑定到 属性 "IsExpanded" 的 Relativesource 模板。 切换按钮有 2 个主要状态:"Checked" 和 "Unchecked" (true/false),扩展器有 2 个主要状态:"Expanded" 和 "Collapsed" (true/false) . 所以基本上我所做的就是告诉 ToggleButton 与它所在的父级共享其 true/false 被选中或未被选中的状态。

完全绑定又是 "{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsChecked}",在英语中基本上是说 "Bind to a related source, and the related source is the parent you're in the template of, and bind so to said template;s "IsChecked" 属性.

最后,我更改了您的触发器,这些触发器需要很长时间才能隐藏 ContentPresenter(试图通过减小它所在的 Grid.Row 的大小来压缩它),而只是告诉它当扩展器的 "IsExpanded"(感谢我们的绑定,ToggleButton 的 "IsChecked")设置为 false 时隐藏,当它们设置为 true 时则相反。

.

关于您的其他问题: 1) ContentSource 用于为 ContentPresenter 提供一个 alias/alternate 名称,我怀疑您很快就会需要它。 属性 名称有点误导,我承认。

2) 正如我们在上面看到的,不 - ToggleButton 需要绑定到模板父级的 "IsExpanded" 属性 才能工作。 如果您要取出按钮,Expander 将不会工作,直到您创建绑定或在代码中发出指令告诉它 open/close。