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 不再可见)。
我做错了什么?
另外我对这个问题有一些疑问:
- "ContentSource="Content"" 有什么作用?它是做什么用的?与 "Content="{模板绑定内容}"" 有何不同?
- 当 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。
我正准备通过创建不同的模板来创建一个新的 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 不再可见)。
我做错了什么?
另外我对这个问题有一些疑问:
- "ContentSource="Content"" 有什么作用?它是做什么用的?与 "Content="{模板绑定内容}"" 有何不同?
- 当 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。